we are developing, with Java library from REST API, a procedure to sign multiple documents where the signature position is set using anchorString in signHereTabs for each signer (anchorString is a string inserted into the document to be signed);
since we have documents with size greater than 25MB, we are using what has been reported in https://developers.docusign.com/esign-rest-api/guides/resource-limits , that is we create a draft envelope (status=created) and then we updates the envelope with the documents;
the problem is that when we set the envelope with status = sent, the signer receives the email, open the link to DocuSign, but only the first document allow to access the anchorString.
Is there any particular way to update the list of documents in the draft envelope ?
Thanks
...
// add a recipient to sign the document, identified by name and email we used above
int recipientId = 0;
List<Signer> signerList = new ArrayList<Signer>();
/* to fix the position where the signature has to be inserted */
int buyerIdx = 0;
int supplierIdx = 0;
for(DSSignerInfo signerInfo : signers) {
Tabs tabs = new Tabs();
Signer signer = new Signer();
signer.setEmail(signerInfo.getEmail());
signer.setName(signerInfo.getName());
signer.setRecipientId(String.valueOf(++recipientId));
signer.setRoutingOrder(String.valueOf(recipientId)); // sequential
signer.setRoleName("role unknown");
RecipientEmailNotification emailNotification = new RecipientEmailNotification();
emailNotification.setEmailBody("emailBody - "+signerInfo.getName());
emailNotification.setEmailSubject("emailSubject - "+signerInfo.getName());
emailNotification.setSupportedLanguage(signerInfo.getLanguage());
signer.setEmailNotification(emailNotification);
// create a signHere tab somewhere on the document for the signer to sign
// default unit of measurement is pixels, can be mms, cms, inches also
for(int documentId = 1; documentId <= documentFiles.size(); documentId++) {
SignHere signHere = new SignHere();
signHere.setDocumentId("" + documentId);
signHere.setPageNumber("1");
signHere.setRecipientId(String.valueOf(recipientId));
if(signerInfo.getRole().equalsIgnoreCase("buyer")) {
signHere.setAnchorString("BUYER_"+buyerIdx);
} else {
signHere.setAnchorString("SUPPLIER_"+supplierIdx);
}
signHere.setAnchorXOffset("10");
signHere.setAnchorYOffset("10");
tabs.addSignHereTabsItem(signHere);
}
signer.setTabs(tabs);
signerList.add(signer);
if(signerInfo.getRole().equalsIgnoreCase("buyer")) {
buyerIdx++;
} else {
supplierIdx++;
}
}
Recipients recipients = new Recipients();
recipients.setSigners(signerList);
envDef.setRecipients(recipients);
try {
String envelopeId = null;
EnvelopesApi envelopesApi = null;
// create a byte array that will hold our document bytes
int documentId = 1;
for(String documentFile : documentFiles) {
byte[] fileBytes = null;
try {
// read file
Path path = Paths.get(documentFile);
fileBytes = Files.readAllBytes(path);
} catch (IOException ioExcp) {
// handle error
System.out.println("Exception: " + ioExcp);
return null;
}
// add a document to the envelope
Document doc = new Document();
String base64Doc = Base64.getEncoder().encodeToString(fileBytes);
doc.setDocumentBase64(base64Doc);
String fileName = new File(documentFile).getName();
doc.setName(documentId+"_"+fileName);
doc.setFileExtension(fileName.lastIndexOf('.') > 0 ? fileName.substring(fileName.lastIndexOf('.') + 1) : "");
doc.setDocumentId("" + documentId++);
envDef.addDocumentsItem(doc);
if(envelopeId == null || envelopesApi == null) {
// To save as a draft set to "created" (for test purpose I create and envelope with only one file)
envDef.setStatus("created");
envelopesApi = new EnvelopesApi();
EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(accountId, envDef);
envelopeId = envelopeSummary.getEnvelopeId();
} else {
// the files after the 1st are updated in the draft envelope
envDef.setRecipients(recipients);
List<Document> tmpDocumentList = new ArrayList<Document>();
doc.setApplyAnchorTabs("true");
tmpDocumentList.add(doc);
envDef.setDocuments(tmpDocumentList);
EnvelopeDocumentsResult envelopeDocumentsResult = envelopesApi.updateDocuments(accountId, envelopeId, envDef);
}
}
Envelope envelope = envelopesApi.getEnvelope(accountId, envelopeId);
envelope.setStatus("sent");
envelope.setPurgeState(null);
EnvelopesApi.UpdateOptions uo = envelopesApi. new UpdateOptions();
uo.setAdvancedUpdate("true");
EnvelopeUpdateSummary envelopeUpdateSummary = envelopesApi.update(accountId, envelopeId, envelope, uo);
documentId = 1;
for(String documentFile : documentFiles) {
Tabs tabs = envelopesApi.getDocumentTabs(accountId, envelopeId, ""+documentId++);
System.out.println("CARLO Tabs 3, documentId "+(documentId - 1)+": "+tabs);
}
Thanks for your answer.
More details:
in the envelope we have more than one document;
the size of each document is less than 25MB;
the sum of the sizes of all the documents is more than 25MB.
We can upload documents in envelope with status "created", but when the status is changed to "sent" and the signer goes into the signature page then it is not required to sign these documents; it seem that the signHereTabs is not set in the documents added while envelope status is "created".
If after having set envelope status = "sent" we execute the following code
documentId = 1;
for(String documentFile : documentFiles) {
Tabs tabs = envelopesApi.getDocumentTabs(accountId, envelopeId, ""+documentId++);
System.out.println("Tabs: documentId "+(documentId - 1)+": "+tabs);
}
we obtain
Tabs: documentId 1: class Tabs {
...
signHereTabs: [class SignHere {
anchorCaseSensitive: null
anchorHorizontalAlignment: null
anchorIgnoreIfNotPresent: null
anchorMatchWholeWord: null
anchorString: BUYER_0
anchorUnits: pixels
anchorXOffset: 10
anchorYOffset: -10
conditionalParentLabel: null
conditionalParentValue: null
customTabId: null
documentId: 1
errorDetails: null
mergeField: null
name: SignHere
optional: false
pageNumber: 1
recipientId: edb96dfd-9700-4328-ba45-825a1284b030
scaleValue: 1.0
stampType: signature
stampTypeMetadata: null
status: null
tabId: e484087c-70c2-431c-9825-47605e1f44c2
tabLabel: Sign Here
tabOrder: null
templateLocked: null
templateRequired: null
tooltip: null
xPosition: 123
yPosition: 297
}]
...
}
Tabs: documentId 2: class Tabs {
...
signHereTabs: []
...
}
where documentId 1 has been uploaded when the envelope has been created (status="created"), and documentId 2 has been uploaded in a second step (both documentId 1 and 2 contain the anchorString: BUYER_0).
If your document size is greater than 25MB then also putting document in the draft mode will not help, instead you have to use ChunkedUploads to add any document less than 50MB. Adding multiple documents via draft is useful if your JSON Request Payload is greater than 25 MB, but it will not be useful if any document in the envelope is greater than 25 MB.
To add on to Amit's answer, every individual API request to DocuSign must be less than 25MB.
Since the default technique is to send Base64 encoded documents within a JSON object, the effective max total size for all of the documents sent in a single request is around 18MB.
You can avoid the Base64 overhead by sending the API request as a multi-part MIME message. This technique enable you to send the documents as binary objects. See the code example for scenario 10 in C# (also available for PHP, Java, Node.js, Python, and Ruby)
Additional
If each of your documents is less than 18 MB, then you can use the "regular" JSON object and Base64 encode one document at a time. If the sum of the document sizes is greater than 18MB then you must upload them one at a time:
Create the envelope, include one of the documents. The document status should be created so the envelope is not sent at this time.
Add more documents to the envelope, one at a time. You can use EnvelopeDocuments::updateList API method. You'd probably want query parameter apply_document_fields on.
Update the envelope status to sent using Envelopes::update
For adding tabs to the documents, you could define them at the beginning if you use anchor tab positioning. Or you could add the tabs to the envelope definition after you finish adding the documents to the envelope.
Thanks all for the answers.
I've solved the problem in this way:
- step 2: set on the parameter apply_document_fields on each added file,
- step 3: set again the recipients in the envelope before set it as 'sent'.
From my point of view this question is solved.
Related
my UI when create and wh
My code to update:
var recipients = envelopesApi.ListRecipients(accountId, envelopeId, new EnvelopesApi.ListRecipientsOptions { includeTabs = true.ToString() });
foreach (var doc in documents)
{
var retornoDelete = envelopesApi.DeleteDocuments(accountId, envelopeId, new EnvelopeDefinition { Documents = new List<Document> { doc } });
}
var resultUpdateDocuments = envelopesApi.UpdateDocuments(accountId, envelopeId, new EnvelopeDefinition { Documents = envelope.Documents, Recipients = recipients });
var resultUpdateRecipients = envelopesApi.UpdateRecipients(accountId, envelopeId, recipients, new EnvelopesApi.UpdateRecipientsOptions { resendEnvelope = "true" });
I have try this link bellow, but not work for me:
DocuSign: Signer Tabs are lost when updating an envelope
Im not sure what you are trying to do in this code, but you are both updating the recipient and the document. It make a lot more sense to create a new envelope at this point, instead of 3 API calls - you can make just one.
The reason you don't see the tab (SignIn) is because you are updating the recipients and documents again and that won't by itself update the tabs. You need to make yet another API call for this (https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopedocumenttabs/update/)
I recommend you reconsider this flow to just create a new envelope with all the information in one call. But if you need to do it this way - you'll need another API call.
the Create Tabs work here, i guess this will sufficient
foreach (var item in recipients.Signers)
{
try
{
var tabsRecipient = envelope.Recipients.Signers.Where(x => x.Email == item.Email).Select(x => x.Tabs).First();
var resultUpdateTabs = envelopesApi.CreateTabs(accountId, envelopeId, item.RecipientId, tabsRecipient);
}
catch (Exception ex)
{
// this recipient have a constraint
}
}
I have problem with prefilling tabs from prefillTabs group while creating envelope using docusign api. It's impossible to assign values through templateRoles, since these tabs do not have any recipientId. Is it possible somehow to assign values to this kind of tabs?
Yes, you can do that, here is how to do that from the C# SDK:
EnvelopeSummary results = envelopesApi.CreateEnvelope(accountId, env);
string envelopeId = results.EnvelopeId;
PrefillTabs prefill = new PrefillTabs();
prefill.TextTabs = new List<Text>();
prefill.TextTabs.Add(new Text { PageNumber = "1", DocumentId = "1", Value = "!!!test-inbar!!!" });
Tabs tabs = new Tabs();
tabs.PrefillTabs = prefill;
envelopesApi.CreateDocumentTabs(accountId, envelopeId, "1", tabs);
Or you can use raw JSON API call this way:
Endpoint:
/restapi/v2.1/accounts/[AccountId]/envelopes/[EnvelopeId]/documents/[DocumentId]/tabs
JSON body:
{"prefillTabs":{"textTabs":[{"value":"!!!test-inbar!!!","pageNumber":1,"documentId":"1","xPosition":316,"yPosition":97}]}}
I'm successfully sending envelopes via the DocuSign eSignature API and have a question about the emails that are sent as part of the signing process. When a request is sent I'm receiving the following emails (using the Sandbox environment):
email to each recipient from dse_demo#docusign.net with a reply to of my name/email address
email to me when each recipient clicks the link to view the agreement to sign (e.g. "John Smith viewed Acme Co Customer Agreement")
email to me (and each recipient) when agreement has been completed.
I'm trying to understand what options are available for each of these as far as:
enabling/disabling each of these emails
changing the email address used for each of these (and if this can be done via the API)
Appreciate any insights into whether and how I can make any changes to these.
The completion emails can be enabled/disabled in the settings for your DocuSign account. This can be found in: Settings > Signing Settings > Envelope Delivery. You can also enable/disable the "envelope viewed" notification emails and completion emails for both the sender and signer in: Settings > Email Preferences.
Which language are you integrating the API with? In C# you can change the email when adding the envelope recipient in the envelope definition e.g.
private static EnvelopeDefinition MakeEnvelope(string recipientEmail)
{
recipientEmail = "recipientEmail#email.com"
byte[] buffer = System.IO.File.ReadAllBytes("filePath");
Document doc1 = new Document();
string b64 = Convert.ToBase64String(buffer);
doc1.DocumentBase64 = b64;
doc1.Name = "Document Name";
doc1.FileExtension = "pdf";
doc1.DocumentId = "1";
env.Documents = new List<Document> { doc1 };
Text textTab = new Text
{
DocumentId = "1",
PageNumber = "1",
XPosition = "168",
YPosition = "513",
Height = "17",
Width = "369",
Value = "envelopeTabText",
Locked = "true"
};
SignHere signer1signhere = new SignHere
{
DocumentId = "1",
PageNumber = "1",
XPosition = "128",
YPosition = "775"
};
**Signer signer1 = new Signer
{
Email = recipientEmail,
Name = "customerName",
RecipientId = "1",
RoutingOrder = "1"
};**
Tabs signer1Tabs = new Tabs
{
TextTabs = new List<Text> { textTab },
SignHereTabs = new List<SignHere> { signer1signhere }
};
signer1.Tabs = signer1Tabs;
Recipients recipients = new Recipients
{
Signers = new List<Signer> { signer1 }
};
env.Recipients = recipients;
env.Status = "sent";
return env;
}
I have the DocuSign API working to pre-fill existing tabs on a template. I am trying to add some additional tabs dynamically for the templaterole signers, but the tabs are not showing up.
Here is my code that I am working with.
string SigningGroupID = "12345";
string RoleName = "Test Signing Group"';
string TemplateId = "XXX-XX-XXXX-XXX";
List<TemplateRole> templateRoles = new List<TemplateRole>();
DocuSign.eSign.Model.Tabs tabs = new DocuSign.eSign.Model.Tabs();
List<Text> TextTabs = new List<Text>();
Text text = new Text();
text.TabLabel = "test_label";
text.XPosition = "100";
text.YPosition = "150";
TextTabs.Add(text);
if (TextTabs.Count > 0) tabs.TextTabs = TextTabs;
TemplateRole doc_signer = new TemplateRole
{
SigningGroupId = SigningGroupID,
RoleName = RoleName,
RoutingOrder = "1",
Tabs = tabs
};
templateRoles.Add(doc_signer);
EnvelopeDefinition envelope = new EnvelopeDefinition();
envelope.EmailSubject = "This is a test";
envelope.Status = "created";
envelope.TemplateId = TemplateId;
envelope.TemplateRoles = templateRoles;
EnvelopesApi envelopeApi = new EnvelopesApi(_apiClient.Configuration);
EnvelopeSummary results = envelopeApi.CreateEnvelope(AccountID, envelope);
Console.WriteLine(results.ToJson());
Do I need some additional items populated on the new Text object (e.g. TabID)? I am not sure why this is not working.
Thanks
jlimited
Correct. You're missing a few properties for your Text object. When you define your Text tab, be sure to connect it to the appropriate recipient, document, and page by specifying the following:
text.documentId
text.pageNumber
text.recipientId
text.xPosition
text.yPosition
text.tabLabel
To determine the three missing values, you can make a request to GET /templates, which will return to you the IDs. SDK method is Templates:get
There are many more properties you can add, but you'll need these to get your tab to display properly.
I have the template setup un the sandbox. Whenever I want to be redirected to demo.docusign.net and take action on the PDF, it is auto-populating the tabs. But my requirement is to simply generate the PDF without redirecting to docusign on click of a button. I am sending user information on click of a button to docusign and it has to generate the auto populated customer data on PDF for viewing (draft version). Currently it is generating the template without any dynamic user data, even though I pass the values. Please let me know, if there is any api to perform this.
Thanks in advance
I'm not completely sure I understand what you're trying to do. But sounds like you want:
1. Remote signing. Not Embedded Signing.
2. Populate values of tabs in templates.
You also didn't specify which coding lang you used, so I'm going to give you some C#. You can find the full code examples in all langs in the links above.
// Step 1: Obtain your OAuth token
var accessToken = RequestItemsService.User.AccessToken; // Represents your {ACCESS_TOKEN}
var accountId = RequestItemsService.Session.AccountId; // Represents your {ACCOUNT_ID}
// Step 2: Construct your API headers
var config = new Configuration(new ApiClient(basePath));
config.AddDefaultHeader("Authorization", "Bearer " + accessToken);
// Step 3: Create Tabs and CustomFields
// Set the values for the fields in the template
// List item
List colorPicker = new List
{
Value = "green",
DocumentId = "1",
PageNumber = "1",
TabLabel = "list"
};
// Checkboxes
Checkbox ckAuthorization = new Checkbox
{
TabLabel = "ckAuthorization",
Selected = "true"
};
Checkbox ckAgreement = new Checkbox
{
TabLabel = "ckAgreement",
Selected = "true"
};
RadioGroup radioGroup = new RadioGroup
{
GroupName = "radio1",
// You only need to provide the readio entry for the entry you're selecting
Radios = new List<Radio> { new Radio { Value = "white", Selected = "true" } }
};
Text includedOnTemplate = new Text
{
TabLabel = "text",
Value = "Jabberywocky!"
};
// We can also add a new tab (field) to the ones already in the template
Text addedField = new Text
{
DocumentId = "1",
PageNumber = "1",
XPosition = "280",
YPosition = "172",
Font = "helvetica",
FontSize = "size14",
TabLabel = "added text field",
Height = "23",
Width = "84",
Required = "false",
Bold = "true",
Value = signerName,
Locked = "false",
TabId = "name"
};
// Add the tabs model (including the SignHere tab) to the signer.
// The Tabs object wants arrays of the different field/tab types
// Tabs are set per recipient/signer
Tabs tabs = new Tabs
{
CheckboxTabs = new List<Checkbox> { ckAuthorization, ckAgreement },
RadioGroupTabs = new List<RadioGroup> { radioGroup },
TextTabs = new List<Text> { includedOnTemplate, addedField },
ListTabs = new List<List> { colorPicker }
};
// Create a signer recipient to sign the document, identified by name and email
// We're setting the parameters via the object creation
TemplateRole signer = new TemplateRole
{
Email = signerEmail,
Name = signerName,
RoleName = "signer",
Tabs = tabs //Set tab values
};
TemplateRole cc = new TemplateRole
{
Email = ccEmail,
Name = ccName,
RoleName = "cc"
};
// Create an envelope custom field to save our application's
// data about the envelope
TextCustomField customField = new TextCustomField
{
Name = "app metadata item",
Required = "false",
Show = "true", // Yes, include in the CoC
Value = "1234567"
};
CustomFields cf = new CustomFields
{
TextCustomFields = new List<TextCustomField> { customField }
};
// Step 4: Create the envelope definition
EnvelopeDefinition envelopeAttributes = new EnvelopeDefinition
{
// Uses the template ID received from example 08
TemplateId = RequestItemsService.TemplateId,
Status = "Sent",
// Add the TemplateRole objects to utilize a pre-defined
// document and signing/routing order on an envelope.
// Template role names need to match what is available on
// the correlated templateID or else an error will occur
TemplateRoles = new List<TemplateRole> { signer, cc },
CustomFields = cf
};
// Step 5: Call the eSignature REST API
EnvelopesApi envelopesApi = new EnvelopesApi(config);
EnvelopeSummary results = envelopesApi.CreateEnvelope(accountId, envelopeAttributes);