How to get emailBlurb from template via DocuSign REST API - docusignapi

If I load all templates via the docuSign api the property emailBlurb is always an empty string, emailSubject is available.
It is a spring boot 2 REST service.
public EnvelopeTemplateResults getAllTemplates() {
// Check if valid token available
loginService.checkToken();
EnvelopeTemplateResults templateResult = new EnvelopeTemplateResults();
TemplatesApi templatesApi = new TemplatesApi(com.docusign.esign.client.Configuration.getDefaultApiClient());
List<EnvelopeTemplateResult> templateList;
try {
TemplatesApi.ListTemplatesOptions options = templatesApi.new ListTemplatesOptions();
options.setInclude("notifications,recipients,custom_fields,folders");
templateResult = templatesApi.listTemplates(configuration.getAccountId(), options);
templateList = templateResult.getEnvelopeTemplates();
templateResult.setEnvelopeTemplates(templateList);
} catch (ApiException e) {
logger.error("Error in get all templates: " + e.getLocalizedMessage());
}
return templateResult;
}

Mike,
Please look in here - https://developers.docusign.com/esign-rest-api/guides/features/templates for information about this.
You can make a GET call (GET /v2.1/accounts/{accountId}/templates/{templateId}) to the template API and the top of the json you get back would look like this:
{
"emailSubject": "DocuSign API - Composite Templates",
"emailBlurb": "Composite Templates Sample 1",
"status": "sent",
(just cut the rest of the json)
where you can find what you need

Related

How can I view a batch of Envelopes' custom fields using C# DocuSign's API

This is a question about using the DocuSign API, with their C# SDK, to send documents to recipients for digital signing, and then tracking the status changes at recipient level. I am having problems relating the status changes to the respective recipients.
There is one recipient per Envelope. I send a batch using the BulkEnvelopesAPI CreateBulkListRequest method. I then get status changes using the EnvelopesAPI ListStatusChanges method. I can see new documents when they have been sent and I can see status changes when the documents are signed.
However, I cannot relate these status changes to my recipients. So I have added a Custom Field to the Envelope to hold a unique value for the recipient. The ListStatusChanges response contains a list of Envelopes and each Envelope contains a CustomField property, but it is always null. I can get the Envelopes individually using the EnvelopesAPI ListCustomFields method, using the Envelope Id from ListStatusChanges, but this would mean a large number of API calls. I am sending about 4000 documents in batches of 1000. If I have to check envelopes individually, I will tend to hit up against the 1000-per hour API call limit.
So my question is: how do I set a Custom Field on the Envelope such that I can see it in the CustomFields property of the ListStatusChanges response Envelopes, without having to invoke the API for each Envelope in turn?
Here are some code extracts that might help:
When I create the BulkSendList, I create placeholders in its Envelope:
var theEnvelopeDefinition = new EnvelopeDefinition
{
TemplateId = myConfiguration["TemplateId"],
EnvelopeIdStamping = "false",
EmailSubject = myConfiguration["EmailSubject"],
Status = "created",
CustomFields = new CustomFields
{
TextCustomFields =
new List<TextCustomField>
{
new() { Name = "FRN" }
}
}
};
:
:
:
myEnvelopeApi.CreateEnvelope(myAccountId, theEnvelopeDefinition);
When I add recipients to the Bulk Send List, I do this:
var theBulkSendingList = new BulkSendingList
{
BulkCopies = new List<BulkSendingCopy>(),
Name = "Adviser Terms of Business Mailing"
};
foreach (ZurichAdvisersDocuSignControl aWorkItem in myWorkItems)
{
var theBulkSendingCopy = new BulkSendingCopy
{
CustomFields = new List<BulkSendingCopyCustomField>
{
new() { Name = "FRN", Value = aWorkItem.FcaRegistrationNumber },
new() { Name = "EmailAddress", Value = aWorkItem.EmailAddress }
},
EmailSubject = "This is a test email",
Recipients = new List<BulkSendingCopyRecipient>
{
new()
{
Name =
$"{aWorkItem.RecipientFirstName} {aWorkItem.RecipientLastName}",
Email = aWorkItem.EmailAddress,
RecipientId =
"1" // this has to match the envelope and possibly also something in the template
}
},
EmailBlurb =
string.Format(
CultureInfo.InvariantCulture,
theEmailBlurb,
theGreeting,
aWorkItem.RecipientFirstName)
};
theBulkSendingList.BulkCopies.Add(theBulkSendingCopy);
}
BulkSendingList theBulkSendList =
myBulkEnvelopesApi.CreateBulkSendList(myAccountId, theBulkSendingList);
myBulkListId = theBulkSendList.ListId;
When I request status changes I do this:
var theEnvelopeApi = new EnvelopesApi(myApiClient);
var theOptions = new EnvelopesApi.ListStatusChangesOptions
{
fromDate = DateTime.Now
.AddDays(-1)
.ToString("yyyy/MM/dd")
};
// Call the API method:
EnvelopesInformation theResults =
theEnvelopeApi.ListStatusChanges(myAccountId, theOptions);
In theResults of that last step, I get a List of Envelopes, which includes the Envelopes sent by the BulkSendList. They all have a null CustomFields property. They do have a CustomFieldsUri property and if I use that in Postman it does show me the CustomField values that I set in CreateBulkSendList. Or I can invoke ListCustomField one Envelope at a time. But either way that would lead to too many API calls.
Any thoughts? Is there a better way to do what I am trying to do? I could just bite the bullet and implement something that manages the 1000-per-hour API call limit, but the existence of BulkSendLists gave me hope that I'd not need to. Or I could filter the ListStatusChanges call to only show Envelopes where the status has progressed beyond Sent since the last time I checked; this would reduce the number of changes returned and so reduce the number of ListCustomFields calls I need to do per hour, but there is still the risk I hit the limit.
Thanks
Steve
https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopes/liststatuschanges/
See this:
Your C# code should change to :
var theOptions = new EnvelopesApi.ListStatusChangesOptions
{
include = "custom_fields",
fromDate = DateTime.Now.AddDays(-1).ToString("yyyy/MM/dd")
};

Unable to create contact with additional id

I am currently using SDK version 3.39.0 and version 0004 of the API_MKT_CONTACT service definition to try to create a new Contact with an AdditionalID in Marketing Cloud with the following code:
ODataRequestUpdate contactRequest =
contactService
.updateContactOriginData(contact)
.withHeader("Sap-Cuan-RequestTimestamp", getFormattedTime(System.currentTimeMillis()))
.withHeader("Sap-Cuan-SequenceId", "UpdatePatch")
.withHeader("Sap-Cuan-SourceSystemType", "EXT")
.withHeader("Sap-Cuan-SourceSystemId", "sdk-test")
.toRequest();
var additionalId =
AdditionalID.builder()
.externalContactID(pii.getId().toString())
.originOfContact(origin)
.originOfContact_2("EMAIL") //ContactAdditionalOrigin
.externalContactID_2(pii.getEmail()) //ContactAdditionalID
.build();
var additionalIdRequest = contactService
.updateAdditionalIDs(additionalId)
.replacingEntity()
.withHeader("Sap-Cuan-RequestTimestamp", getFormattedTime(System.currentTimeMillis()))
.withHeader("Sap-Cuan-SourceSystemType", "EXT")
.withHeader("Sap-Cuan-SourceSystemId", "sdk-test")
.toRequest();
// use low level API as a work around for https://github.com/SAP/cloud-sdk/issues/156
ODataRequestBatch requestBatch = new ODataRequestBatch(ContactService.DEFAULT_SERVICE_PATH, ODataProtocol.V2);
requestBatch
.beginChangeset()
.addUpdate(contactRequest)
.addUpdate(additionalIdRequest)
.endChangeset();
HttpClient httpClient = HttpClientAccessor.getHttpClient(contactsDestination);
ODataRequestResultMultipartGeneric batchResult = requestBatch.execute(httpClient);
batchResult.getResult(additionalIdRequest);
This results in the following error:
{
"error": {
"code": "SY/530",
"message": {
"lang": "en",
"value": "Inline component is not defined or not allowed (HTTP PUT)"
},
"innererror": {
"application": {
"component_id": "CEC-MKT-DM-IC",
"service_namespace": "/SAP/",
"service_id": "API_MKT_CONTACT_SRV",
"service_version": "0004"
},
"transactionid": "3B63A2A6CC9205E0E00604E1D31F1CDF",
"timestamp": "20210315142401.8432680",
"Error_Resolution": {
"SAP_Transaction": "For backend administrators: use ADT feed reader \"SAP Gateway Error Log\" or run transaction /IWFND/ERROR_LOG on SAP Gateway hub system and search for entries with the timestamp above for more details",
"SAP_Note": "See SAP Note 1797736 for error analysis (https://service.sap.com/sap/support/notes/1797736)",
"Batch_SAP_Note": "See SAP Note 1869434 for details about working with $batch (https://service.sap.com/sap/support/notes/1869434)"
},
"errordetails": []
}
}
}
I am using this documentation as a guide for building my requests (under the section "Create Contacts with Additional IDs"). When I run the example code in Postman it works as expected. Note that the payload for the AdditionalIDs is an empty JSON object.
So I enabled HTTP wire logs and noticed that the SDK seems to be including the following payload:
PUT AdditionalIDs(ContactAdditionalOrigin='EMAIL',ContactAdditionalID='wade.watts#theoasis.com',ContactID='ae46e174-52a3-4de6-8caa-57213151b295',ContactOrigin='<CONTACT_ORIGIN>') HTTP/1.1
Sap-Cuan-SourceSystemId: sdk-test
Accept: application/json
Sap-Cuan-SourceSystemType: EXT
Content-Type: application/json
Sap-Cuan-RequestTimestamp: '2021-03-15T14:24:00.828'
{"ContactOrigin":"<CONTACT_ORIGIN>","ContactID":"ae46e174-52a3-4de6-8caa-57213151b295","ContactAdditionalOrigin":"EMAIL","ContactAdditionalID":"wade.watts#theoasis.com","ContactAdditionalIdUUID":null,"ContactUUID":null,"ContactAddlIDIsInvalid":null,"MarketingAreas":[]}
Unfortunately, I can't seem to find a way to omit the payload/inline component while using the SDK so that it matches the example code. Is this an issue with the SDK or am I doing something wrong? Any help would be much appreciated!
Cheers!
UPDATE
Applying the suggested workaround from #matkuhr I changed my additionalIdRequest above to this and it worked:
ODataEntityKey key = new ODataEntityKey(ODataProtocol.V2)
.addKeyProperty(AdditionalID.EXTERNAL_CONTACT_ID.getFieldName(), mcContact.getContactId())
.addKeyProperty(AdditionalID.ORIGIN_OF_CONTACT.getFieldName(), origin)
.addKeyProperty(AdditionalID.ORIGIN_OF_CONTACT_2.getFieldName(), "EMAIL")
.addKeyProperty(AdditionalID.EXTERNAL_CONTACT_I_D_2.getFieldName(), mcContact.getEmailAddress());
var request = new ODataRequestUpdate(
ContactService.DEFAULT_SERVICE_PATH,
"AdditionalIDs",
key,
"{}",
UpdateStrategy.REPLACE_WITH_PUT,
null,
ODataProtocol.V2);
request.addHeader("Sap-Cuan-RequestTimestamp", getFormattedTime(System.currentTimeMillis()));
request.addHeader("Sap-Cuan-SourceSystemType", "EXT");
request.addHeader("Sap-Cuan-SourceSystemId", "sdk-test);
It's not you doing something wrong, it's also not the SDK, it's the service. The service seems to substantially deviate from the OData V2 conventions as well as basic HTTP conventions.
You can work around this by leveraging the low-level APIs of the SDK even more. Create the update request fully manually with the payload the service requires, e.g.:
ODataEntityKey key = new ODataEntityKey(ODataProtocol.V2)
.addKeyProperty(Contact.XYZ.getFieldName(), contact.getXyz())
request = new ODataRequestUpdate(
contactService.getServicePath(),
contact.getEntityCollection(),
key,
"{ }", // this will be the payload
UpdateStrategy.REPLACE_WITH_PUT,
null,
ODataProtocol.V2);
request.addHeader("key", "val");
// add more headers & parameters if needed and execute

DocuSign REST API DELETE method requires a body

For example to remove a member from a signing group you call:
/restapi/v2/accounts/1686083/signing_groups/{groupId}/users
and provide:
{
"users": [
{
"userName": "sample string 1",
"email": "sample string 2"
}
]
}
as the body
But my REST object (in ServiceNow) does not allow me to provide a body when I'm using the delete method. Am I just stuck?
I don't think there is any another way to remove the user from a SigningGroup using API. You can try to update the user in a Signing group to a Dummy Email so that original user will not get email for signing. And once in a while DS Admin can go to WEBApp and manually delete it, if Service now is not allowing DS API delete operation with a body.
If you're using RestMessageV2 in ServiceNow scripted Outbound REST, there's a setRequestBody method you can use to set the request body as a string:
Example in the docs here
var sm = new sn_ws.RESTMessageV2("Update user","post");
var body = "{ ...Message body content... }";
sm.setRequestBody(body);

Docusign REST API: Downloading document to string

I am building an app using the docusign API and PHP. I have most of this working except I cannot figure out how to download the document. I have been searching on this site and on the Docusign site. Docusign has an example here, that shows how to get a list of docs in PHP, but the downloading does not have a PHP example. In the Docusign REST API docs they explain the method here. But this says the response is "PDF File".
In my sample code below, I have tried to put the contents into a file, but it creates and empty file. If I print_r($data), I get this:
SplFileObject Object
(
[pathName:SplFileInfo:private] => /tmp/419ULk
[fileName:SplFileInfo:private] => 419ULk
[openMode:SplFileObject:private] => w
[delimiter:SplFileObject:private] => ,
[enclosure:SplFileObject:private] => "
)
It does create the file in /tmp, but I want to keep the document in a string so I send or save to DB.
Here is my controller function:
public function get_document($envelopeId, $cert = FALSE)
{
$save_dir = BASEPATH."../documents/";
if ($envelopeId) {
$this->load->model('docusign_model');
$data = $this->docusign_model->get_document($envelopeId, $cert);
}
file_put_contents($save_dir.$envelopeId.".pdf", $data);
//print_r($data);
die("116");
}
This is in docusign_model:
public function get_document($envelopeId, $cert)
{
$docuSignAuth = $this->auth();
if ($docuSignAuth) {
$envelopeApi = new EnvelopesApi($docuSignAuth->apiClient);
$options = new GetDocumentOptions();
if($cert) {
$options->setCertificate(TRUE);
} else {
$options->setCertificate(FALSE);
}
return $envelopeApi->getDocument($docuSignAuth->accountId, 1, $envelopeId, $options);
}
return false;
}
How can I get this document and keep it in a string?
Any and all help is greatly appreciated!
The content comes back as a file, you have to read the temp file and save that to the desired file
Quick snippet using file_get_contents and file_put_contents
$docStream = $envelopeApi->getDocument($accountId, 1, $envelopeId);
file_put_contents("my_document.pdf", file_get_contents($docStream->getPathname()));
More info DocuSign REST API :: EnvelopeDocuments: get under Get a Single Document as a PDF File

Issue with Token in createAndSend function

I have been building some pdf forms and using docusign for signatures. The issue I am having with the current one is that docusign goes to "finished" after my 2nd signer signs. The logs show that it is not sending to my 3rd signer but I am unsure how to code the getToken to include the 3rd signer after the 2nd has signed.
Any advice would be very helpful.
if ($_SERVER["REQUEST_METHOD"] == "POST") {
//$GLOBALS['_oneSigner'] = isset($_POST["autorefill"]);
createAndSend();
if(!$GLOBALS['_oneSigner']){
$GLOBALS['_showTwoSignerMessage'] = true;
}
} else if ($_SERVER["REQUEST_METHOD"] == "GET") {
if (isset($_GET["envelopeID"])) {
// Display a message that we are moving on to Signer Number 2
// - unless the message is suppressed (by signing from the GetStatusAndDocs page)
if(isset($_GET['from_gsad'])){
getToken(getStatus($_GET['envelopeID']),$_GET['clientID']);
}else{
$GLOBALS['_showTransitionMessage'] = true;
getToken(getStatus($_GET['envelopeID']),2);
}
} else {
$_SESSION["embedToken"] = "";
}
}
To prevent an email sending and using "Embedded Signing" you need to specify a clientUserId that would tell DocuSign not to send the email and instead expect a call to generate embedded signing url.
See complete code example here - https://developers.docusign.com/esign-rest-api/guides/features/embedding

Resources