We're looking at is downloading the combined pdf and then extracting the individual documents ( not my idea ). I tried using pdfsharp against my combined pdf, but I don't see any title information on the individual documents. I was just wondering if this is even possible. If I use pdfsharp, it can pull out all the pages, but I have no way of really knowing which pages belong with with document.
After you create a DocuSign envelope you can read the document information from the envelope and remember the page counts for each document. This should also work if you are using Templates.
You can use the EnvelopeDocuments: list API to get the document information, which includes pages for each doc. Then when you need to extract the individual documents from the combined PDF you'll know where to separate the individual docs.
Here's a sample API response for the list documents call:
{
"envelopeDocuments": [
{
"availableDocumentTypes": [
{
"isDefault": "true",
"type": "electronic"
}
],
"display": "inline",
"documentId": "1",
"includeInDownload": "true",
"name": "NDA.pdf",
"order": "1",
"pages": "3",
"signerMustAcknowledge": "no_interaction",
"type": "content",
"uri": "/envelopes/44efc9e6-915e-4b1d-9b54-801410d6922d/documents/1"
},
{
"availableDocumentTypes": [
{
"isDefault": "true",
"type": "electronic"
}
],
"display": "inline",
"documentId": "2",
"includeInDownload": "true",
"name": "House.pdf",
"order": "2",
"pages": "1",
"signerMustAcknowledge": "no_interaction",
"type": "content",
"uri": "/envelopes/44efc9e6-915e-4b1d-9b54-801410d6922d/documents/2"
},
{
"availableDocumentTypes": [
{
"isDefault": "true",
"type": "electronic"
}
],
"display": "inline",
"documentId": "3",
"includeInDownload": "true",
"name": "contractor_agreement.docx",
"order": "3",
"pages": "2",
"signerMustAcknowledge": "no_interaction",
"type": "content",
"uri": "/envelopes/44efc9e6-915e-4b1d-9b54-801410d6922d/documents/3"
},
{
"availableDocumentTypes": [
{
"isDefault": "true",
"type": "electronic"
}
],
"display": "inline",
"documentId": "certificate",
"includeInDownload": "true",
"name": "Summary",
"order": "999",
"pages": "4",
"signerMustAcknowledge": "no_interaction",
"type": "summary",
"uri": "/envelopes/44efc9e6-915e-4b1d-9b54-801410d6922d/documents/certificate"
}
],
"envelopeId": "44efc9e6-915e-4b1d-9b54-801410d6922d"
}
The getEnvelopeDocuments api has an option to download all the documents in an envelope as a zip file. You can just unzip the file and get individual documents.
GET /v2/accounts/{accountId}/envelopes/{envelopeId}/documents/archive
Retrieve a ZIP archive that contains all of the PDF documents, the certificate, and any .WAV files used for voice authentication.
Here is a sample code to download zip file and unzip it using the Docusign C# SDK.
Full Example here.
var envApi = new EnvelopesApi();
// GetDocument() API call returns a MemoryStream
var docStream = envApi.GetDocument(accountId, envelopeId, "archive");
// let's save the document to local file system
string zipName = Path.GetRandomFileName();
string zipfilePath = #"C:\temp\" + zipName + ".zip";
using (var fs = new FileStream(zipfilePath, FileMode.Create))
{
docStream.Seek(0, SeekOrigin.Begin);
docStream.CopyTo(fs);
}
string extractPath = #"c:\temp\" + zipName;
System.IO.Compression.ZipFile.ExtractToDirectory(zipfilePath, extractPath);
Edit(By Kathy-Lori)
For some reason, I had a problem casting the Stream to a FileStream object. What I did instead was the following:
Stream docStream = envApi.GetDocument(AccountId, envelopeId, "archive");
MemoryStream ret = new MemoryStream();
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = docStream.Read(buffer, 0, buffer.Length)) > 0)
{
ret.Write(buffer, 0, bytesRead);
}
ret.Position = 0;
using (var fs = new FileStream(#"C:\temp\envelopeDocuments.zip", FileMode.Create))
{
ret.CopyTo(fs);
}
Related
I am using composite templates to create an envelope. Every template will only have one document. I need to individually process every document that comes back signed. In order to do that I need to add metadata to each document that is being sent. How can I do that while also using composite templates before I send the envelope?
I know all about envelope metadata and custom fields but what if I need it more specific to documents and I'm not working with the actual documents? Here I'm working with the templates that contain the documents.
Here is the c# code I have so far
List<CompositeTemplate> compositeTemplates = new List<CompositeTemplate>();
Recipients recipientsServerTemplate = new Recipients();
List<Signer> signers = new List<Signer>();
List<CarbonCopy> carbonCopies = new List<CarbonCopy>();
Signer signer1 = new Signer();
signer1.Email = signerEmail;
signer1.Name = signerName;
signer1.RoleName = "signer";
signer1.RecipientId = "1";
signer1.Tabs = tabs;
signers.Add(signer1);
CarbonCopy cc1 = new CarbonCopy();
cc1.Email = ccEmail;
cc1.Name = ccName;
cc1.RoleName = "cc";
cc1.RecipientId = "2";
carbonCopies.Add(cc1);
recipientsServerTemplate.Signers = signers;
recipientsServerTemplate.CarbonCopies = carbonCopies;
int i = 1;
foreach (string templateId in templateIds)
{
//add custom fields //this is per envelope. I need it more specific in my case
TextCustomField textcustomField = new TextCustomField
{
Name = "MyCustomField" + i.ToString(),
Required = "false",
Show = "false",
Value = "653022"
};
CustomFields cf = new CustomFields
{
TextCustomFields = new List<TextCustomField> { textcustomField }
};
List<ServerTemplate> ServerTemplates = new List<ServerTemplate>();
List<InlineTemplate> InlineTemplates = new List<InlineTemplate>();
CompositeTemplate CT = new CompositeTemplate
{
CompositeTemplateId = i.ToString()
};
ServerTemplate ST = new ServerTemplate
{
Sequence = i.ToString(),
TemplateId = templateId
};
InlineTemplate IT = new InlineTemplate
{
Recipients = recipientsServerTemplate,
Sequence = (i+1).ToString(),
CustomFields = cf//this is for the whole envelope
};
InlineTemplates.Add(IT);
ServerTemplates.Add(ST);
CT.ServerTemplates = ServerTemplates;
CT.InlineTemplates = InlineTemplates;
compositeTemplates.Add(CT);
i++;
}
EnvelopeDefinition env = new EnvelopeDefinition
{
Status = "sent",
CompositeTemplates = compositeTemplates
};
I suggest adding metadata at the envelope level about the envelope's documents. I don't think you can add document-level metadata when using composite templates.
Added
Templates are usually created via the DocuSign web app. But the web app does not support document-level metadata.
When you use the API to create the envelope, you could create add additional fields to the documents. You could make those additional fields only readable to your company recipients and store document metadata there.
But I would not recommend that. Better to store the document-specific data at the envelope level. For example, include the document-specific metadata as a JSON string in the envelope-level metadata:
...
"compositeTemplates": [
{
"serverTemplates": [
{
"sequence": "1",
"templateId": "61973947-7d29-490d-9bac-5432154321"
}
],
"inlineTemplates": [
{
"sequence": "2",
"customFields": {
"textCustomFields": [
{
"name": "Main document",
"show": "false",
"value": "{\"value\":34500, \"office\": \"SF\"}"
}
]
},
Adding metadata on the envelope about my documents was not a robust option as I knew nothing about the document that I could connect my metadata to
What I ended up doing to track individual documents within templates was adding a read-only text tab with "MetaDataId" as the tab label for each of my documents that I had in templates.
Read-only tabs don't replicate data across the envelope.
The JSON request would look like
{
"compositeTemplates": [
{
"compositeTemplateId": "FirstTemplate",
"serverTemplates": [
{
"sequence": "1",
"templateId": "templateId1"
}
],
"inlineTemplates": [
{
"sequence": "1",
"recipients": {
"signers": [
{
"email": "blah#blah.com",
"name": "Blah Blah",
"recipientId": "1",
"roleName": "Signer",
"routingOrder": "1",
"tabs": {
"textTabs": [
{
"tabLabel": "MetaDataId",
"value": "121"
}
]
}
}
]
}
}
]
},
{
"compositeTemplateId": "SecondTemplate",
"serverTemplates": [
{
"sequence": "2",
"templateId": "templateId2"
}
],
"inlineTemplates": [
{
"sequence": "2",
"recipients": {
"signers": [
{
"email": "blah#blah.com",
"name": "Blah Blah",
"recipientId": "1",
"roleName": "Signer",
"routingOrder": "1",
"tabs": {
"textTabs": [
{
"tabLabel": "MetaDataId",
"value": "122"
}
]
}
}
]
}
}
]
},
{
"compositeTemplateId": "ThirdTemplate",
"serverTemplates": [
{
"sequence": "3",
"templateId": "templateId3"
}
],
"inlineTemplates": [
{
"sequence": "3",
"recipients": {
"signers": [
{
"email": "blah#blah.com",
"name": "Blah Blah",
"recipientId": "1",
"roleName": "Signer",
"routingOrder": "1",
"tabs": {
"textTabs": [
{
"tabLabel": "MetaDataId",
"value": "123"
}
]
}
}
]
}
}
]
}
],
"emailSubject": "Please Sign",
"emailBlurb": "This is an email Example",
"status": "sent"
}
Incidentally, if you're using the C# SDK and you're creating the templates with a loop as I am doing in the question for this post then you may have to clone the object that you're setting for the Recipients the in Inline Template so that the value you set for the MetaDataId text tab for the signer doesn't just hold the last one that you assigned, which will happed if you reuse the same Recipients object.
What I want is to place the custom fields at document level while creating the template so that later I can have unique values for every envelope that is created. These values should be visible to all the recipients.
These are the steps that I currently follow:
Create Document Custom Fields/Tab Definitions at the Account level.
Create the template from our app and navigate to DocuSign to place the above created custom fields on the document (it is signer specific).
Save the template.
At a later stage, choose the template in our app and create an envelope with the template ID, templateRoles (with custom fields' values for signer), status etc. like below:
{
"templateId": "1e6c1118-1234-1244-1244-c4a11111775b",
"templateRoles": [
{
"roleName": "Signer1",
"name": "Signer1",
"email": "Signer1#Signer1.com",
"tabs": {
"textTabs": [
{
"tabLabel": "Account.Name",
"value": "account-name777"
},
{
"tabLabel": "Candidate.FullName",
"value": "candidate-name1234"
},
{
"tabLabel": "Candidate.Mobile",
"value": "0412347777"
}
]
}
},
{
"roleName": "Signer2",
"name": "Signer2",
"email": "Signer2#Signer2.com",
"tabs": {
"textTabs": [
{
"tabLabel": "Account.Name",
"value": "account-name777"
},
{
"tabLabel": "Candidate.FullName",
"value": "candidate-name1234"
},
{
"tabLabel": "Candidate.Mobile",
"value": "0412347777"
}
]
}
}
],
"status": "sent"
}
The above works for Signer1 but does not show the custom fields' values to Signer2. The custom fields need to be exactly the same for all recipients. Is there a way to achieve this?
Also what I noticed was after Signer1 signs the document then the custom fields' values show to Signer2.
Change the tabLabels so they are not the same, here is the code:
{
"templateId": "1e6c1118-1234-1244-1244-c4a11111775b",
"templateRoles": [
{
"roleName": "Signer1",
"name": "Signer1",
"email": "Signer1#Signer1.com",
"tabs": {
"textTabs": [
{
"tabLabel": "Account.Name1",
"value": "account-name777"
},
{
"tabLabel": "Candidate.FullName1",
"value": "candidate-name1234"
},
{
"tabLabel": "Candidate.Mobile1",
"value": "0412347777"
}
]
}
},
{
"roleName": "Signer2",
"name": "Signer2",
"email": "Signer2#Signer2.com",
"tabs": {
"textTabs": [
{
"tabLabel": "Account.Name2",
"value": "account-name777"
},
{
"tabLabel": "Candidate.FullName2",
"value": "candidate-name1234"
},
{
"tabLabel": "Candidate.Mobile2",
"value": "0412347777"
}
]
}
}
],
"status": "sent"
}
This is my JSON code so far:
{
"status": "sent",
"emailSubject": "This is an api Demo Doc, sent for signature",
"recipients": {
"carbonCopies": [
{
"email": "nila#gmail.com",
"name": "Nilashree",
"recipientId": "2"
}
],
"signers": [
{
"email": "{{signer1Email}}",
"name": "Nilashree Nandkumar shirodkar",
"recipientId": "1"
}
]
},
"compositeTemplates": [
{
"inlineTemplates": [
{
"sequence": "1",
"recipients": {
"signers": [
{
"email": "nshiro2#students.towson.edu",
"name": "Nila Joseph",
"recipientId": "1",
"defaultRecipient": "true"
}
]
}
}
],
"documents": {
"documentId": "1",
"name": "application_form.pdf",
"transformPdfFields": "true",
"documentBase64": "{{}}"
}
}
]
}
But I am getting the following error:
"errorCode": "ENVELOPE_IS_INCOMPLETE",
"message": "The Envelope is not Complete. A Complete Envelope Requires Documents, Recipients, Tabs, and a Subject Line."
Can anyone please let me know what am I doing wrong?
Why are you using a composite template? Perhaps you are planning towards a later, more complicated envelope definition.
Your mistake is that each composite template can optionally contain only one document. The field name is document, not documents.
Instead of
"documents": {
"documentId": "1",
"name": "application_form.pdf",
"transformPdfFields": "true",
"documentBase64": "{{}}"
}
use
"document": {
"documentId": "1",
"name": "application_form.pdf",
"transformPdfFields": "true",
"documentBase64": "{{}}"
}
Also, I don't believe there's a need for the recipients outside of the composite templates structure. I'm not 100% sure about this issue though.
I want to add a new key-value pair in JSON object with nunjucks template, but unable to add it(don't want to add any custom filter).
suppose I have an object
var obj = {"id": "1", "name": "test", "child": {"id": "2", "status": "true"},
"template": "{{obj.child}}"}
Now I want to add a new key like
{"template": "{% set json = obj.child %}{% set json.name = 'testing' %}"}
So the final output as I want
{
"id": "1",
"name": "test",
"child": {
"id": "2",
"status": "true"
},
"template": {
"id": "2",
"status": "true",
"name": "testing"
}
}
Please let me how can I do?
I am creating envelopes from a template. I need to know the documentIds that will be created in the envelope ahead of time so I can deal with a strange special case prefilling radio buttons. (I can explain why in more detail, but it's not really relevant to this question.)
So where do these document IDs come from? I am using the REST api for all of this.
This is my template:
GET https://demo.docusign.net/restapi/v2/accounts/{{accountId}}/templates/78b351c5-84f8-49c9-af48-redacted
{
"envelopeTemplateDefinition": {
"templateId": "78b351c5-84f8-49c9-af48-redacted",
"name": "my dev template",
.... truncated for brevity ....
},
"documents": [
{
"documentId": "73370178",
"uri": "/envelopes/78b351c5-84f8-49c9-af48-redacted/documents/73370178",
"name": "DS_Testing_Doc1.pdf",
"order": "1",
"pages": "1"
},
{
"documentId": "13535052",
"uri": "/envelopes/78b351c5-84f8-49c9-af48-redacted/documents/13535052",
"name": "DS_Testing_Doc2.pdf",
"order": "2",
"pages": "1"
}
],
"recipients": {
.... truncated for brevity ....
}
}
This is my Create Envelope from Template call:
POST https://demo.docusign.net/restapi/v2/accounts/{{accountId}}/envelopes/
{ "envelopeId":null,
"accountId":"redacted",
"templateId":"78b351c5-84f8-49c9-af48-redacted",
"status":"sent",
"templateRoles":[
{
"id":null,
"roleName":"producer",
"email":"myemail#mycompany.com",
"name":"Eric",
"clientUserId":"",
"status":"sent",
"tabs":{
.... truncated for brevity ....
}
},
{
"id":null,
"roleName":"hidden",
"email":"myemail2#mycompany.com",
"name":"My Agent",
"clientUserId":"",
"status":"created",
"tabs":{
.... truncated for brevity ....
}
}
],
"voidedReason":null
}
Response from creating envelope:
{
"envelopeId": "2ab1e693-6f30-4f93-9902-redacted",
"uri": "/envelopes/2ab1e693-6f30-4f93-9902-redacted",
"statusDateTime": "2016-01-26T20:41:59.2400000Z",
"status": "sent"
}
Now get the details about Documents in the envelope:
GET https://demo.docusign.net/restapi/v2/accounts/{{accountId}}/envelopes/2ab1e693-6f30-4f93-9902-redacted/documents
{
"envelopeId": "2ab1e693-6f30-4f93-9902-redacted",
"envelopeDocuments": [
{
"documentId": "1",
"name": "DS_Testing_Doc1.pdf",
"type": "content",
"uri": "/envelopes/2ab1e693-6f30-4f93-9902-redacted/documents/1",
"order": "1",
"pages": "1",
"availableDocumentTypes": [
{
"type": "electronic",
"isDefault": "true"
}
]
},
{
"documentId": "2",
"name": "DS_Testing_Doc2.pdf",
"type": "content",
"uri": "/envelopes/2ab1e693-6f30-4f93-9902-redacted/documents/2",
"order": "2",
"pages": "1",
"availableDocumentTypes": [
{
"type": "electronic",
"isDefault": "true"
}
]
},
{
"documentId": "certificate",
"name": "Summary",
"type": "summary",
"uri": "/envelopes/2ab1e693-6f30-4f93-9902-redacted/documents/certificate",
"order": "999",
"pages": "1",
"availableDocumentTypes": [
{
"type": "electronic",
"isDefault": "true"
}
]
}
]
}
In the final call where I view details about Documents in the Envelope, the IDs are "1" and "2". However, in my template, the documentIDs are "73370178" and "13535052".
So, how do documentIds get assigned when creating an Envelope from a template? Do they correspond to 'order' in the template, as they appear to? Can I rely on them always starting at 1 incrementing from there?
Is it possible to define the documentIds in my template and have them be the same when I create an Envelope?
Is it possible to assign the documentIds when creating the envelope from the template (assuming the PDF is uploaded to the template, not sending the whole PDF byte stream)?
Cheers
The documentId is actually completely up to you - it's a client defined value and takes a string so really you can use any naming standard you want (i.e. numbers, letters, or a combo). Many integrations use simple numbers (1, 2, 3, etc.) for the documentIds whereas others others use strings or other identifiers.
In any case, you just need to remember what value you set for a given a document if you want to later assign a radio tab to a recipient of that document.
Note: If you do NOT provide a documentId when creating an envelope the system will automatically generate and assign an GUID as the documentId, you can then make the Get Documents API call to retrieve that ID.