So I am building a crm/docusign/crm integration. The flow is as follows:
Salesperson clicks a button that takes them to a page on my server(scala play framework instance) that generates and sends the envelope for the document that the user can sign.
Document is sent to user for signing.
Once signed, Write the data back to the crm to each contact/lead/company, depending on field names mapped from docusign to the crm.
This is all working fine and dandy. Problem is, if there are more than 1 contact, they should all get the SAME docusign document and all be signers on it. I am not 100% sure this is even possible, or really why 2 of the same documents is an issue for the client, but it appears to be. The funky part about all of this is I CAN add more than 1 signer at the moment to the same envelope id, but the document is only editable by the first contact on the lead. Everyone else that gets it can't edit it. Once marked finished by the only person that can sign it, it just has their information on it for the other signers and is in read only mode still.
My question is is there any way this is possible? I am assuming that it isn't since each envelope id can really only relate to a single signer. It doesn't even make sense to me how a second signer could sign the same document with the same envelope id and put in different data and it maintain the integrity of both signers since envelope id seems to be a sort of session for the document. If anyone has any experience with the docusign API, I'd really appreciate some insight on this!
Code I'm using:
private def makeEnvelope(contacts: List[Contact], accountInfo: AccountInfo, leadId:Int, whichForm:FORMTYPE) = {
val env = new EnvelopeDefinition
val eventNotification = new EventNotification
eventNotification.setUrl(callbackURL) // fake var name for privacy
env.setTemplateId(templateId)
eventNotification.setRequireAcknowledgment("true")
eventNotification.setIncludeDocuments("true")
eventNotification.setLoggingEnabled("true")
var envelopeEvents : List[EnvelopeEvent]= List.empty[EnvelopeEvent]
val envelopeEvent = new EnvelopeEvent
envelopeEvent.setEnvelopeEventStatusCode("completed")
envelopeEvent.setIncludeDocuments("true")
envelopeEvents = envelopeEvent :: envelopeEvents
eventNotification.setEnvelopeEvents(envelopeEvents.asJava)
env.setEventNotification(eventNotification)
var signerList = List[TemplateRole]()
for(contact <- contacts) {
val signer1 = new TemplateRole
val signEmail = contact.email
signer1.setEmail(signEmail)
signer1.setName(contact.fullName)
signer1.setRoleName("Signatory")
val showAddress: Boolean = contacts.length == 1
// tabs is some data from crm to map to prepopulate docusign when user signs form
val tabs = populateFormData(accountInfo, contact, whichForm, showAddress)
signer1.setTabs(tabs)
signerList = signer1 :: signerList
}
env.setTemplateRoles(signerList.asJava)
env.setStatus("sent")
env
}
If you want a dynamic number of signers for the envelopes (envelope 1 has one signer, envelope 2 has two signers) then do not use a template.
Instead, create the entire envelope object on the fly so it will fit the needs of each envelope. Eg, the envelope object for envelope 2 will include two signer recipients with each having (at least) a sign_here tab.
If you don't know how to create an envelope object that includes two signer recipient objects, ask a new stackOverflow question.
Related
I have integrated DocuSign embedded signing into my web app, which is still in development so using DocuSign developer sandbox.
When an envelope is created programmatically, I am including Name, Email and ClientUserId for the signer like this:
var signers = new List<TemplateRole>();
foreach (var r in req.Recipients)
{
var signer = new TemplateRole();
signer.ClientUserId = r.SSOUserId;
signer.Email = r.Email;
signer.Name = r.Name;
signer.RoleName = r.RoleName;
signer.RoutingOrder = r.RoutingOrder.ToString();
signer.Tabs = r.MergeFields
signers.Add(signer);
}
var env = new EnvelopeDefinition()
{
TemplateId = ...,
TemplateRoles = new List<TemplateRole>(signers),
EventNotification = ...,
Status = "Sent"
};
When an embedded recipient view is requested, I include the same exact Name, Email and ClientUserId in the request like this:
var envelopeApi = new EnvelopesApi(ApiClient);
var viewOptions = new RecipientViewRequest
{
ReturnUrl = ...,
AuthenticationMethod = "Password",
ClientUserId = recipient.SSOUserId,
UserName = recipient.Name,
Email = recipient.Email
};
var viewUrl = envelopeApi.CreateRecipientView(AccountId, DocuSignEnvelopeId, viewOptions);
Even though the user may change their Name and/or Email in my app, I have the original values saved in a table and I use those original values when requesting the view from DocuSign. This setup has worked 100% of the time for many months until now when an envelope is having trouble obtaining a recipient view. The envelope was created + viewed last week (April 27, 2022), and when the user tried to sign it today (May 4, 2022), they keep getting this error:
DocuSign.eSign.Client.ApiException: Error calling CreateRecipientView: {
"errorCode":"UNKNOWN_ENVELOPE_RECIPIENT",
"message":"The recipient you have identified is not a valid recipient of the specified envelope."
}
Note that hundreds of envelopes created before and after the above envelope are still able to obtain a recipient view with the exact same code + configuration. The problematic envelope has not expired, I can still see it in the Waiting for Others section of the DocuSign admin site. I have compared its recipient info at DocuSign (by invoking ListRecipients) with the info I have in my database, and the Name, Email, ClientUserId, RoleName, RoutingOrder all match completely. My account is set up to expire envelopes after 120 days, and I am not doing anything during envelope creation to set an expiration date. I have seen many others having this issue but typically their problem is the ClientUserId. My code has that handled, and it works for every other envelope.
The only difference I have seen between this envelope and the others is that ListRecipients results show the affected envelope as having a property
"signatureInfo": {
"fontStyle": "docusign7",
"signatureInitials": "RW",
"signatureName": "Test"
}
that is null for all other envelopes. The documentation states that this property can be set by the sender to pre-fill signature fields. However, I didn't even know about this property before today, so my app has never set it. It would be weird for this property to cause the envelope to be in a state where it cannot be signed anymore but I am struggling to find a reason why this particular envelope cannot be signed. Btw, the signatureName of Test actually matches the Name property of the recipient so its even more confusing why DocuSign is refusing to recognize the signer.
If the envelope is still active, I suggest doing a Recipients:list operation. Also check that the recipient is a "current" recipient. (If there's only one recipient, then this doesn't apply.)
If the Recipients:list doesn't give you any clues then I suggest you contact developer support. They can check our backend logs to see if there's additional information on why the RecipientsView call didn't work.
See page https://support.docusign.com/s/contactSupport?language=en_US First login to that page if you have a production account. You can get support if you only have a developer account.
I've setup a developer sandbox environment of DocuSign. Using its C#.NET API Client, I want to send a document for signing to client's more than one personal email ids. Once the client opens any email to see and sign it, the corresponding DocuSign envelope state should get updated to Completed.
Also, I tried to achieve the above behavior through multiple signer recipients, but the envelope state gets marked completed, when all the signer recipients sign the document. Here I want any signer recipient sign should be enough to complete the document signing workflow.
Please suggest how to get it done
Regards,
A
In order to deliver an envelope to several emails in a single role, you'll need to create a Signing Group. Signing Groups can be created and managed through the API, so you'll be able to do that programatically.
While you'll need to implement your own business logic and error checking, a sample of creating a Signing Group in c# looks like:
SigningGroup signingGroup = new SigningGroup();
signingGroup.GroupName = "SigningGroup_" + DateTime.UtcNow.Ticks.ToString();
signingGroup.GroupType = "sharedSigningGroup";
signingGroup.Users = new List<SigningGroupUser>();
SigningGroupUser signingGroupUser1 = new SigningGroupUser();
signingGroupUser1.UserName = "Example Signer";
signingGroupUser1.Email = "signer#example.com";
signingGroup.Users.Add(signingGroupUser1);
SigningGroupUser signingGroupUser2 = new SigningGroupUser();
signingGroupUser2.UserName = "Example Signer";
signingGroupUser2.Email = "personal.email#example.com";
signingGroup.Users.Add(signingGroupUser2);
SigningGroupInformation signingGroupInformation = new SigningGroupInformation();
signingGroupInformation.Groups = new List<SigningGroup> { signingGroup };
SigningGroupsApi signingGroupsApi = new SigningGroupsApi(apiClient.Configuration);
SigningGroupInformation newGroupInfo = signingGroupsApi.CreateList(accountId, signingGroupInformation);
string newGroupId = newGroupInfo.Groups[0].SigningGroupId;
To use the Signing Group in an envelope, define a signer with that group ID:
Signer signer = new Signer
{
SigningGroupId = newGroupId,
RecipientId = "1",
RoutingOrder = "1"
};
Once the envelope is created as a draft, you can then clean up the signing group:
signingGroupsApi.DeleteList(accountId, newGroupInfo);
I have this thing working for like 2 years. Then it stopped sending emails to the signers after they signed a document. By the way the document is created from a widget embedded method.
I'm using the PHP SDK of the docusign API. And here's a summary of my code
$envelopeApi = new \DocuSign\eSign\Api\EnvelopesApi($apiClient);
$document = new \DocuSign\eSign\Model\Document();
$document->setDocumentBase64("My document template");
$document->setName("My template name);
$document->setDocumentId("randomly generated document ID");
// creates the sign here
$signHere = new \DocuSign\eSign\Model\SignHere();
$signHere->setAnchorString("Signature:");
$signHere->setAnchorIgnoreIfNotPresent("false");
$signHere->setAnchorUnits("pixels");
$signHere->setAnchorYOffset("50");
$signHere->setAnchorXOffset("5");
$signHere->setDocumentId("The document ID");
$signHere->setRecipientId("The recipient ID, randomly generated");
// add the signature tab to the envelope's list of tabs
$tabs = new \DocuSign\eSign\Model\Tabs();
$tabs->setSignHereTabs(array($signHere));
// add the signer to the envelope
$signer = new \DocuSign\eSign\Model\Signer();
$signer->setName("Recipient Name");
$signer->setEmail("Recipient Email");
$signer->setRecipientId("The recipient ID");
$signer->setTabs($tabs);
$signer->setClientUserId("The client user ID");
// Add a recipient to sign the document
$recipients = new \DocuSign\eSign\Model\Recipients();
$recipients->setSigners(array($signer));
$envelop_definition = new \DocuSign\eSign\Model\EnvelopeDefinition();
$envelop_definition->setEmailSubject("Mail subject");
// set envelope status to "sent" to immediately send the signature request
$envelop_definition->setStatus("sent");
$envelop_definition->setRecipients($recipients);
$envelop_definition->setDocuments(array($document));
// create and send the envelope! (aka signature request)
$envelopeApi->createEnvelope("Owner account ID", $envelop_definition, null);
I knew that by adding the envelope definition status "sent" would send a copy to the signer but thats not the case. Did something happened recently on the API that I have to adapt? I checked the documentation but still the same. So I'm not sure if I'm doing the right thing.
Any help would be greatly appreciated. Thanks in advance.
By setting a ClientUserId for your signer, you are creating a Captive Recipient. If you want DocuSign to do email delivery, remove the ClientUserId parameter and a Remote Recipient will be created instead.
Each envelope type will have its own email subject/body that is static for that envelope type. Here is an example of a few predetermined envelope types:
Mortgage closing documents
Mortgage loan application documents
These envelopes will contain a varied number of documents and each document is unique. I've attempted to create a template without a document, but it appears that is not allowed.
I'd like to be able to save the email body and subject for these envelope types so that when I send an envelope via the DocuSign API, I don't have to directly specify these fields. I'm hoping to avoid storing the subject/body inside of code or a configuration file. Preferably, I'd like a non-technical person to be able to change the subject/body through the DocuSign interface.
What I ended up doing:
Based on Kim Brandl's recommendations, I wrote the following code which worked as expected. A few notes:
The initial file that you added to the template will not appear in the final envelope if the ServerTemplate sequence is greater than the InlineTemplate. You can read more here.
The Recipients, signers, documents, etc., follow the same pattern as a standard EnvelopeDefinition except the data is placed under the InlineTemplate.
string docBase64 = Convert.ToBase64String(file.Stream.ReadAsBytes());
EnvelopeDefinition envDef = New EnvelopeDefinition();
envDef.Status = "created";
// The first sequence that appears will be the first document that is applied.
// If you want the uploaded documents to appear instead of the server template,
// make the server template a higher number.
envDef.CompositeTemplates = new List<CompositeTemplate>
{
new CompositeTemplate()
{
ServerTemplates = new List<ServerTemplate>()
{
new ServerTemplate("2", templateId)
},
InlineTemplates = new List<InlineTemplate>()
{
new InlineTemplate()
{
Sequence = "1",
Recipients = new Recipients()
{
Signers = new List<Signer>()
{
new Signer()
{
Email = request.Recipients[0].UserEmail,
Name = request.Recipients[0].UserName,
RoleName = request.Recipients[0].RoleName,
RecipientId = (1).ToString()
}
}
},
Documents = new List<Document>()
{
new Document()
{
DocumentBase64 = docBase64,
DocumentId = "3",
Name = "ConsentFake.pdf",
IncludeInDownload = "true"
},
new Document
{
DocumentBase64 = docBase64,
DocumentId = "9",
Name = "ConsentFake2.pdf",
IncludeInDownload = "true"
}
}
}
}
}
};
Summary: This allowed me to take advantage of a DocuSign template's email subject/body without having to use a specific template document.
You can implement a solution for the scenario that you've described by doing the following:
Using the DocuSign web UI, create a Template for each 'type of Envelope' and specify the Email Subject and Body in each Template that you create. You'll also need to upload a document to the Template (DocuSign requires that you add at least one document before you can save the Template) -- but you can just add any placeholder doc (for example, a .txt file that contains the word placeholder file). The document you add to the template won't actually be used in the Envelopes that you create from the Template -- since you'll use the API to specify documents at runtime. (Non-technical folks will be able to use the DocuSign web UI to modify/update the email info in each Template at any point in the future.)
When sending an Envelope via the API, use the compositeTemplates structure in the "Create Envelope" API request. By using the compositeTemplates structure, you can specify the serverTemplate to use (which will pull in the Email Subject and Email Body that you've defined in that Template), specify recipient and tab info by using the inlineTemplate object, and specify document info using the document object.
(There's lots of info available here on Stack Overflow about how to use compositeTemplates in the Create Envelope request. If you have trouble getting that request structure correct/working, please post a separate question.)
I have created a DocuSign envelope from template. I have stored the envelope id for future operations. Using this envelope id I can only retrieve the envelope that I have created but I need the template id too. Is there any way to retrieve the template id from envelope or FolderItems? Please help :(
I'm not sure if you create an envelope from a Template if the templateId is saved as meta data anywhere in the envelope (I don't believe it is). As such you can simply do that yourself - try using Envelope Custom Fields to store the templateId at the time of creation, and that templateId will then be stored as meta data on that envelope throughout it's lifecycle.
Do a search in the DocuSign API Documentation to find out more about "Envelope Custom Fields". For example, here is the page for how to create them.
Thank you #Ergin. I have tried to implement your idea and it is working. But there are some other issues whatever I have done. I am sharing some parts of my code.
//Getting available folder list of my DocuSign account.
DocuSignServiceRef.AvailableFolders folders = DocuSignHelper.GetDocuSignServiceClient().GetFolderList(new DocuSignServiceRef.FoldersFilter { AccountId = DocuSignHelper.UserID });
//Creating a FolderFilter item to get folder items using this filter.
DocuSignServiceRef.FolderFilter filter = new DocuSignServiceRef.FolderFilter();
filter.AccountId = DocuSignHelper.UserID;
filter.FolderTypeInfo = new DocuSignServiceRef.FolderTypeInfo();
filter.FolderTypeInfo = folders.Folders[1].FolderTypeInfo; //Filter Send Items
//Getting sent items
DocuSignServiceRef.FolderResults results = DocuSignHelper.GetDocuSignServiceClient().GetFolderItems(filter);
if (results != null && results.ResultSetSize > 0)
{
foreach (DocuSignServiceRef.FolderItem item in results.FolderItems)
{
foreach (DocuSignServiceRef.RecipientStatus recipient in item.RecipientStatuses)
{
//Filtering items by Recipient
if (recipient.Email.Equals(RecipientEmail))
{
//Getting envelope of the folder item
DocuSignServiceRef.Envelope sentEnvelope = DocuSignHelper.GetDocuSignServiceClient().RequestEnvelope(item.EnvelopeId, false);
if (sentEnvelope.CustomFields != null)
{
//Checking envelope's custom fields for template id
foreach (DocuSignServiceRef.CustomField customField in sentEnvelope.CustomFields)
{
if (string.Equals(customField.Name, "TemplateID"))
{
if (customField.Value == "{CurrentTemplateID}")
{
HasAlreadySignedSameTemplate = true;
//I will not request the recipient for another signature on same template.
}
}
}
}
}
}
}
}
The above code is working for me. But it is taking too much time to load all Sent items. I can't see any way to set recipient information in FolderFilter. If I can set the recipient's email in filter at the first while I am loading Sent Items then time will be saved for me. Otherwise this code will get unusable.
Have you any idea about modifying my implementation?
If you are creating envelopes with a REST call you can retrieve the info with a call templatesv2/accounts/:accountId/envelopes/:envelopeId/templates
Have a go in the envelope tab. I noticed that envelopes created with a SOAP sdk don't have this information filled in.