How to properly create templates using Docusign via cURL and PHP - docusignapi
I want to create templates for document signing using docusign in PHP. It seems their API is not fully detail.
Docusign for template creation
I have followed their instructions and have obtained my access token, base_url etc via cURL in PHP.
Here is the PHP code they provide without further details. No PHP SDK and how to use it. I couldn't find were to use my access_token, base_url etc as per documentation.
private function make_template_req(): EnvelopeTemplate
{
$doc_file = 'World_Wide_Corp_fields.pdf';
$content_bytes = file_get_contents(self::DEMO_DOCS_PATH . $doc_file);
$base64_file_content = base64_encode($content_bytes);
# Create the document model
$document = new Document([ # create the DocuSign document object
'document_base64' => $base64_file_content,
'name' => 'Lorem Ipsum', # can be different from actual file name
'file_extension' => 'pdf', # many different document types are accepted
'document_id' => '1' # a label used to reference the doc
]);
# Create the signer recipient model
# Since these are role definitions, no name/email:
$signer = new Signer([
'role_name' => 'signer', 'recipient_id' => "1", 'routing_order' => "1"]);
# create a cc recipient to receive a copy of the documents
$cc = new CarbonCopy([
'role_name' => 'cc', 'recipient_id' => "2", 'routing_order' => "2"]);
# Create fields using absolute positioning
# Create a sign_here tab (field on the document)
$sign_here = new SignHere(['document_id' => '1', 'page_number' => '1',
'x_position' => '191', 'y_position' => '148']);
$check1 = new Checkbox(['document_id' => '1', 'page_number' => '1',
'x_position' => '75', 'y_position' => '417', 'tab_label' => 'ckAuthorization']);
$check2 = new Checkbox(['document_id' => '1', 'page_number' => '1',
'x_position' => '75', 'y_position' => '447', 'tab_label' => 'ckAuthentication']);
$check3 = new Checkbox(['document_id' => '1', 'page_number' => '1',
'x_position' => '75', 'y_position' => '478', 'tab_label' => 'ckAgreement']);
$check4 = new Checkbox(['document_id' => '1', 'page_number' => '1',
'x_position' => '75', 'y_position' => '508', 'tab_label' => 'ckAcknowledgement']);
$list1 = new ModelList([
'font' => "helvetica",
'font_size' => "size11",
'anchor_string' => '/l1q/',
'anchor_y_offset' => '-10', 'anchor_units' => 'pixels',
'anchor_x_offset' => '0',
'list_items' => [
['text' => "Red" , 'value' => "red" ], ['text' => "Orange", 'value' => "orange"],
['text' => "Yellow", 'value' => "yellow"], ['text' => "Green" , 'value' => "green" ],
['text' => "Blue" , 'value' => "blue" ], ['text' => "Indigo", 'value' => "indigo"]
],
'required' => "true",
'tab_label' => "l1q"
]);
$number1 = new Number(['document_id' => "1", 'page_number' => "1",
'x_position' => "163", 'y_position' => "260",
'font' => "helvetica", 'font_size' => "size14", 'tab_label' => "numbersOnly",
'width' => "84", 'required' => "false"]);
$radio_group = new RadioGroup(['document_id' => "1", 'group_name' => "radio1",
'radios' => [
new Radio(['page_number' => "1", 'x_position' => "142", 'y_position' => "384",
'value' => "white", 'required' => "false"]),
new Radio(['page_number' => "1", 'x_position' => "74", 'y_position' => "384",
'value' => "red", 'required' => "false"]),
new Radio(['page_number' => "1", 'x_position' => "220", 'y_position' => "384",
'value' => "blue", 'required' => "false"])
]]);
$text = new Text(['document_id' => "1", 'page_number' => "1",
'x_position' => "153", 'y_position' => "230",
'font' => "helvetica", 'font_size' => "size14", 'tab_label' => "text",
'height' => "23", 'width' => "84", 'required' => "false"]);
# Add the tabs model to the signer
# The Tabs object wants arrays of the different field/tab types
$signer->setTabs(new Tabs(['sign_here_tabs' => [$sign_here],
'checkbox_tabs' => [$check1, $check2, $check3, $check4], 'list_tabs' => [$list1],
'number_tabs' => [$number1], 'radio_group_tabs' => [$radio_group], 'text_tabs' => [$text]
]));
# Template object:
$template_request = new EnvelopeTemplate([
'description' => "Example template created via the API",
'name' => $this->template_name,
'shared' => "false",
'documents' => [$document], 'email_subject' => "Please sign this document",
'recipients' => new Recipients([
'signers' => [$signer], 'carbon_copies' => [$cc]]),
'status' => "created"
]);
return $template_request;
}
$results = $templates_api->createTemplate($args['account_id'], $template_req_object);
I decided to use cURL but they provide Bash code in Step 2 (Create Template) and cURL code in Step 3 (Call the eSignature REST API) which is confusing.
I decide to combine Bash Code and Curl code in php to see if it will work but it throws error.
$access_token='access_token goes here';
$base_uri='my base url goes here';
$account_id ='my account id goes here';
$data_param=
'{
"description": "Example template created via the API",
"name": "Example Signer and CC template",
"shared": "false",
"documents": [
{
"documentBase64": "' > $request_data
cat $doc1_base64 >> $request_data
printf '",
"documentId": "1", "fileExtension": "pdf",
"name": "Lorem Ipsum"
}
],
"emailSubject": "Please sign this document",
"recipients": {
"carbonCopies": [
{"recipientId": "2", "roleName": "cc", "routingOrder": "2"}
],
"signers": [
{
"recipientId": "1", "roleName": "signer", "routingOrder": "1",
"tabs": {
"checkboxTabs": [
{
"documentId": "1", "pageNumber": "1",
"tabLabel": "ckAuthorization", "xPosition": "75",
"yPosition": "417"
},
{
"documentId": "1", "pageNumber": "1",
"tabLabel": "ckAuthentication", "xPosition": "75",
"yPosition": "447"
},
{
"documentId": "1", "pageNumber": "1",
"tabLabel": "ckAgreement", "xPosition": "75",
"yPosition": "478"
},
{
"documentId": "1", "pageNumber": "1",
"tabLabel": "ckAcknowledgement", "xPosition": "75",
"yPosition": "508"
}
],
"listTabs": [
{
"documentId": "1", "font": "helvetica",
"fontSize": "size14",
"listItems": [
{"text": "Red", "value": "red"},
{"text": "Orange", "value": "orange"},
{"text": "Yellow", "value": "yellow"},
{"text": "Green", "value": "green"},
{"text": "Blue", "value": "blue"},
{"text": "Indigo", "value": "indigo"},
{"text": "Violet", "value": "violet"}
],
"pageNumber": "1", "required": "false",
"tabLabel": "list", "xPosition": "142",
"yPosition": "291"
}
],
"radioGroupTabs": [
{
"documentId": "1", "groupName": "radio1",
"radios": [
{
"pageNumber": "1", "required": "false",
"value": "white", "xPosition": "142",
"yPosition": "384"
},
{
"pageNumber": "1", "required": "false",
"value": "red", "xPosition": "74",
"yPosition": "384"
},
{
"pageNumber": "1", "required": "false",
"value": "blue", "xPosition": "220",
"yPosition": "384"
}
]
}
],
"signHereTabs": [
{
"documentId": "1", "pageNumber": "1",
"xPosition": "191", "yPosition": "148"
}
],
"textTabs": [
{
"documentId": "1", "font": "helvetica",
"fontSize": "size14", "height": 23,
"pageNumber": "1", "required": "false",
"tabLabel": "text", "width": 84,
"xPosition": "153", "yPosition": "230"
},
{
"documentId": "1", "font": "helvetica",
"fontSize": "size14", "height": 23,
"pageNumber": "1", "required": "false",
"tabLabel": "numbersOnly", "width": 84,
"xPosition": "153", "yPosition": "260"
}
]
}
}
]
},
"status": "created"
}';
$url ="$base_uri/v2.1/accounts/$account_id/templates";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', "Authorization: Bearer $access_token"));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_param);
//curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$output = curl_exec($ch);
echo $output;
Updated part of the code
After installing PHP SDK and run my sample code below, it throws error
<?php
require_once('vendor/autoload.php');
$access_token='my token goes here';
$base_path='https://demo.docusign.net';
$account_id ='my account id goes here';
// You will need to obtain an access token using your chosen authentication flow
$api_client = new \DocuSign\eSign\client\ApiClient($base_path);
$config = new \DocuSign\eSign\Model\Configuration($api_client);
$config->addDefaultHeader('Authorization', 'Bearer ' + $access_token);
$users_api = new \DocuSign\eSign\Api\UsersApi($api_client);
?>
Error:
Fatal error: Uncaught TypeError: DocuSign\eSign\Client\ApiClient::__construct(): Argument #1 ($config) must be of type ?DocuSign\eSign\Configuration, string given, called in C:\xampp\htdocs\docusign-esign\index.php on line 9 and defined in C:\xampp\htdocs\docusign-esign\vendor\docusign\esign-client\src\Client\ApiClient.php:91 Stack trace: #0 C:\xampp\htdocs\docusign-esign\index.php(9): DocuSign\eSign\Client\ApiClient->__construct('https://demo.do...') #1 {main} thrown in C:\xampp\htdocs\docusign-esign\vendor\docusign\esign-client\src\Client\ApiClient.php on line 91
When I run the entire code as per below, it throws error
<?php
require_once('vendor/autoload.php');
$access_token='my access token';
$base_path='https://demo.docusign.net';
$account_id ='my account id goes here';
private function make_template_req(): EnvelopeTemplate
{
// You will need to obtain an access token using your chosen authentication flow
$api_client = new \DocuSign\eSign\client\ApiClient($base_path);
$config = new \DocuSign\eSign\Model\Configuration($api_client);
$config->addDefaultHeader('Authorization', 'Bearer ' + $access_token);
$users_api = new \DocuSign\eSign\Api\UsersApi($api_client);
$doc_file = 'World_Wide_Corp_fields.pdf';
$content_bytes = file_get_contents(self::DEMO_DOCS_PATH . $doc_file);
$base64_file_content = base64_encode($content_bytes);
# Create the document model
$document = new Document([ # create the DocuSign document object
'document_base64' => $base64_file_content,
'name' => 'Lorem Ipsum', # can be different from actual file name
'file_extension' => 'pdf', # many different document types are accepted
'document_id' => '1' # a label used to reference the doc
]);
# Create the signer recipient model
# Since these are role definitions, no name/email:
$signer = new Signer([
'role_name' => 'signer', 'recipient_id' => "1", 'routing_order' => "1"]);
# create a cc recipient to receive a copy of the documents
$cc = new CarbonCopy([
'role_name' => 'cc', 'recipient_id' => "2", 'routing_order' => "2"]);
# Create fields using absolute positioning
# Create a sign_here tab (field on the document)
$sign_here = new SignHere(['document_id' => '1', 'page_number' => '1',
'x_position' => '191', 'y_position' => '148']);
$check1 = new Checkbox(['document_id' => '1', 'page_number' => '1',
'x_position' => '75', 'y_position' => '417', 'tab_label' => 'ckAuthorization']);
$check2 = new Checkbox(['document_id' => '1', 'page_number' => '1',
'x_position' => '75', 'y_position' => '447', 'tab_label' => 'ckAuthentication']);
$check3 = new Checkbox(['document_id' => '1', 'page_number' => '1',
'x_position' => '75', 'y_position' => '478', 'tab_label' => 'ckAgreement']);
$check4 = new Checkbox(['document_id' => '1', 'page_number' => '1',
'x_position' => '75', 'y_position' => '508', 'tab_label' => 'ckAcknowledgement']);
$list1 = new ModelList([
'font' => "helvetica",
'font_size' => "size11",
'anchor_string' => '/l1q/',
'anchor_y_offset' => '-10', 'anchor_units' => 'pixels',
'anchor_x_offset' => '0',
'list_items' => [
['text' => "Red" , 'value' => "red" ], ['text' => "Orange", 'value' => "orange"],
['text' => "Yellow", 'value' => "yellow"], ['text' => "Green" , 'value' => "green" ],
['text' => "Blue" , 'value' => "blue" ], ['text' => "Indigo", 'value' => "indigo"]
],
'required' => "true",
'tab_label' => "l1q"
]);
$number1 = new Number(['document_id' => "1", 'page_number' => "1",
'x_position' => "163", 'y_position' => "260",
'font' => "helvetica", 'font_size' => "size14", 'tab_label' => "numbersOnly",
'width' => "84", 'required' => "false"]);
$radio_group = new RadioGroup(['document_id' => "1", 'group_name' => "radio1",
'radios' => [
new Radio(['page_number' => "1", 'x_position' => "142", 'y_position' => "384",
'value' => "white", 'required' => "false"]),
new Radio(['page_number' => "1", 'x_position' => "74", 'y_position' => "384",
'value' => "red", 'required' => "false"]),
new Radio(['page_number' => "1", 'x_position' => "220", 'y_position' => "384",
'value' => "blue", 'required' => "false"])
]]);
$text = new Text(['document_id' => "1", 'page_number' => "1",
'x_position' => "153", 'y_position' => "230",
'font' => "helvetica", 'font_size' => "size14", 'tab_label' => "text",
'height' => "23", 'width' => "84", 'required' => "false"]);
# Add the tabs model to the signer
# The Tabs object wants arrays of the different field/tab types
$signer->setTabs(new Tabs(['sign_here_tabs' => [$sign_here],
'checkbox_tabs' => [$check1, $check2, $check3, $check4], 'list_tabs' => [$list1],
'number_tabs' => [$number1], 'radio_group_tabs' => [$radio_group], 'text_tabs' => [$text]
]));
# Template object:
$template_request = new EnvelopeTemplate([
'description' => "Example template created via the API",
'name' => $this->template_name,
'shared' => "false",
'documents' => [$document], 'email_subject' => "Please sign this document",
'recipients' => new Recipients([
'signers' => [$signer], 'carbon_copies' => [$cc]]),
'status' => "created"
]);
return $template_request;
}
$results = $templates_api->createTemplate($args['account_id'], $template_req_object);
?>
Error:
Parse error: syntax error, unexpected token "private", expecting end of file in C:\xampp\htdocs\docusign-esign\index.php on line 9
I couldn't find were to use my access_token, base_url etc as per
documentation
Here is how to use $access_token and $base_path, assuming you already obtained it using OAuth.
# You will need to obtain an access token using your chosen authentication flow
$api_client = new \DocuSign\eSign\client\ApiClient($base_path);
$config = new \DocuSign\eSign\Model\Configuration($api_client);
$config->addDefaultHeader('Authorization', 'Bearer ' + $access_token);
$users_api = new \DocuSign\eSign\Api\UsersApi($api_client);
Related
Shopware; setting the product-cover programmatically
i am trying to set the cover of a product programmatically, by doing this for example; [ "name" => "Example product" "price" => [ 0 => [ "currencyId" => "b7d2554b0ce847cd82f3ac9bd1c0dfca" "gross" => 15 "net" => 10 "linked" => false ] ] "manufacturer" => [ "name" => "Example manufacturer" ] "tax" => [ "name" => "21%" "taxRate" => 21 ] "stock" => 6235 "productNumber" => "PE-123123" "coverId" => "4efd6bc156014cc2945b6351d3e9ff03" ] I checked, and i am sure the media is uploaded. If i do it via the media as showed bellow, the media/image gets linked correctly. "media" => [ "Id" => 'Example", "mediaId" => "4efd6bc156014cc2945b6351d3e9ff03" ] I don't understand why it is going wrong, as the documentation (https://docs.shopware.com/en/shopware-platform-dev-en/admin-api-guide/writing-entities#setting-the-cover) prescribes this way. A example in the documentation is the following; { "name": "test", "productNumber": "random", "stock": 10, "taxId": "5f78f2d4b19f49648eb1b38881463da0", "price": [ { "currencyId" : "b7d2554b0ce847cd82f3ac9bd1c0dfca", "gross": 15, "net": 10, "linked" : false } ], "coverId": "00a9742db2e643ccb9d969f5a30c2758" }
You should pass cover media ID in the following way: [ //other product data "cover" => [ "mediaId" => "00a9742db2e643ccb9d969f5a30c2758" ] ] For me, it works.
"media": [ { "id": 'YourProductUuid', "media": { "id": 'YourProductMediaId' } } ], "cover" : { "mediaId" : 'YourProductMediaId' },
Create an envelope with different visibility of documents for users
I generate an envelope of 10-15 documents. There are two end users, the user that will sign should not see document 1 with the data of the second user. The second is to see all the documents. I tried to use "excludedDocuments", but I come across the error "ACCOUNT_LACKS_PERMISSIONS". The example I am generating (incomplete) {"compositeTemplates": [ { "inlineTemplates": [ { "sequence": "1", "recipients": { "signers": [ { "email": "albert#princeton.edu", "name": "Albert Einstein", "recipientId": "1", "clientUserId": "albert#princeton.edu", "routingOrder": "1", "tabs": { "textTabs": [], "radioGroupTabs": [], "checkboxTabs": [] } } ] } } ], "document": { "documentId": 1, "name": "FirstFile", "transformPdfFields": "true" } }, { "inlineTemplates": [ { "sequence": "1", "recipients": { "signers": [ { "email": "albert#princeton.edu", "name": "Albert Einstein", "recipientId": "1", "clientUserId": "albert#princeton.edu", "routingOrder": "1", "tabs": { "textTabs": [], "radioGroupTabs": [], "checkboxTabs": [] } } ] } } ], "document": { "documentId": 2, "name": "SecondFile", "transformPdfFields": "true" } } ]} Please tell me how to solve this problem. Thank you in advance upd PHP7 code: $compositeTemplates[] = [ 'inlineTemplates' => [ [ 'sequence' => '1', 'recipients' => [ 'signers' => [ [ 'email' => $userData['email'], 'name' => $userData['name'], 'recipientId' => '1', 'clientUserId' => $userData['email'], 'routingOrder' => '1', "excludedDocuments" => ['1'], 'tabs' => [ 'textTabs' => Template::fileTextTabs($sendData[$withoutExtension]['text'] ?? false), //here the simple formation of tabs according to what is 'radioGroupTabs' => Template::fileRadioGroupTabs($sendData[$withoutExtension]['radio'] ?? false), 'checkboxTabs' => Template::fileCheckboxTabs($sendData[$withoutExtension]['checkbox'] ?? false), ], ], ], "carbonCopies" => [ [ "email" => 'mylyrium#gmail.com', "name" => 'copies', "recipientId" => "2", "routingOrder" => '1', ], ], ], ], ], 'document' => [ 'documentId' => $id, 'name' => $filename, 'transformPdfFields' => 'true', ], ]; $id++;
This error means that the Admin account is not properly configured to have the document visibility enabled. To do so, go to your DocuSign Admin Account and scroll down to Sending Settings. Make sure that one of the below options is selected instead of Off For more information on the Document Visibility drop-down options, see the official documentation
Docusign API server templates local docs and tabs
I'm working on a DocuSign integration. I have the basics functional but can't seem to figure out how to merge a local document (PDF) with a server template such that tabs configured on the server template get used or overlaid on the passed document. My template is defined on the server and I can use it directly from the web UI without issue (it's a W4 form). The template has three tabs (SSN, Sign here, and date) as you can see below. Accessing this template via it's ID using the API Explorer yields the following json { "envelopeTemplateDefinition": { "templateId": "_redacted_", "name": "W4 3/13/2017", "shared": "true", "password": "", "description": "", "lastModified": "2017-06-05T18:45:28.4470000Z", "lastModifiedBy": { "userName": "Andrew", "userId": "_redacted_", "email": "my_email_address", "uri": "/users/_redacted_ }, "pageCount": 2, "uri": "/templates/_redacted_", "folderName": "Templates", "folderId": "_redacted_", "folderUri": "/folders/_redacted_", "owner": { "userName": "Andrew", "userId": "_redacted_", "email": "my_email_address" } }, "documents": [ { "documentId": "46677269", "uri": "/envelopes/_redacted_/documents/46677269", "name": "W4.pdf", "order": "1", "pages": "2", "display": "inline", "includeInDownload": "true", "signerMustAcknowledge": "no_interaction", "templateLocked": "false", "templateRequired": "false", "documentGroup": "content" } ], "emailSubject": "Please DocuSign: W4.pdf", "emailBlurb": "", "signingLocation": "online", "autoNavigation": "true", "envelopeIdStamping": "true", "authoritativeCopy": "false", "notification": { "reminders": { "reminderEnabled": "false", "reminderDelay": "0", "reminderFrequency": "0" }, "expirations": { "expireEnabled": "true", "expireAfter": "120", "expireWarn": "0" } }, "enforceSignerVisibility": "false", "enableWetSign": "true", "allowMarkup": "false", "allowReassign": "true", "recipients": { "signers": [ { "defaultRecipient": "false", "tabs": { "signHereTabs": [ { "stampType": "signature", "name": "SignHere", "tabLabel": "Signature _redacted_", "scaleValue": 1.0, "optional": "false", "documentId": "46677269", "recipientId": "94043042", "pageNumber": "1", "xPosition": "193", "yPosition": "682", "tabId": "_redacted_", "templateLocked": "false", "templateRequired": "false" } ], "dateSignedTabs": [ { "name": "DateSigned", "value": "", "tabLabel": "Date Signed _redacted_", "font": "lucidaconsole", "fontColor": "black", "fontSize": "size9", "documentId": "46677269", "recipientId": "94043042", "pageNumber": "1", "xPosition": "480", "yPosition": "713", "tabId": "_redacted_", "templateLocked": "false", "templateRequired": "false" } ], "ssnTabs": [ { "validationPattern": "", "validationMessage": "", "shared": "false", "requireInitialOnSharedChange": "false", "requireAll": "false", "value": "", "width": 144, "required": "true", "locked": "false", "concealValueOnDocument": "true", "disableAutoSize": "false", "maxLength": 4000, "tabLabel": "Text _redacted_", "font": "lucidaconsole", "fontColor": "black", "fontSize": "size9", "documentId": "46677269", "recipientId": "94043042", "pageNumber": "1", "xPosition": "442", "yPosition": "563", "tabId": "_redacted_", "templateLocked": "false", "templateRequired": "false" } ] }, "signInEachLocation": "false", "name": "", "email": "", "recipientId": "94043042", "accessCode": "", "requireIdLookup": "false", "routingOrder": "1", "note": "", "roleName": "New Employee", "deliveryMethod": "email", "templateLocked": "false", "templateRequired": "false", "inheritEmailNotificationConfiguration": "false" } ], "agents": [ ], "editors": [ ], "intermediaries": [ ], "carbonCopies": [ ], "certifiedDeliveries": [ ], "inPersonSigners": [ ], "recipientCount": "1" } } What I want to do is apply this template to a PDF that's already partially filled out such that when the signer get's it the tabs defined in the server template are used for the sining. As it stands now, there's nothing. Just the partially filled out PDF I passed in below as base64 data, with none of the server template tabs to fill out or sign. Here's my json for the API call (in PHP). $data = array ( "emailBlurb" => "Test Email Body", "emailSubject" => "Test Email Subject", "status" => "sent", "compositeTemplates" => array(array( "document" => array( "documentId" => 46677269, "name" => $documentName, "documentBase64" => $document ), "serverTemplates" => array(array( "sequence" => 1, "templateId" => "_redacted_" )), "inlineTemplates" => array(array( "sequence" => 2, "recipients" => array( "signers" => array(array( "email" => $recipientEmail, "name" => $recipientName, "recipientId" => $recipientID, "roleName" => "New Employee" )) ) )) )) ); //$data = array... I suspect that I'm simply missing some appropriate reference to the tabs defined in the server template. But documentation is atrocious and I've already spent several hours combing the web. Any help would be much appreciated. UPDATE1 As requested, here's the code that generates the envelope successfully: function c_requestSignature($templateID, $recipientName, $recipientEmail, $recipientID, $document){ //function sets up the passed document for signing using the specified template $documentName = "W4"; //FIXME fetch document name using templateID $baseURL = c_docusignBaseURL(); $accountId = c_docusignAccountId(); $header = c_docusignHeader(); $data = array ( "emailSubject" => "Please sign " . $documentName, //"emailBlurb" => "Test Email Body", "status" => "sent", "compositeTemplates" => array( "compositeTemplate" => array( "serverTemplates" => array( "serverTemplate" => array( "sequence" => "1", "templateId" => "_redacted_" ) ), "inlineTemplates" => array( "inlineTemplate" => array( "sequence" => "2", "recipients" => array( "signers" => array( "signer" => array( "name" => $recipientName, "email" => $recipientEmail, "roleName" => "NewHire" ) ) ) ) ), "document" => array( "documentId" => "1", "name" => $documentName, "fileExtension" => "pdf", "documentBase64" => $document ) ) ) ); // Send to the /envelopes end point, which is relative to the baseUrl received above. $curl = curl_init($baseURL . "/envelopes" ); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Content-Length: ' . strlen($data_string), "X-DocuSign-Authentication: $header" ) ); $json_response = curl_exec($curl); // Do it! $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ( $status != 201 ) { echo "Error calling DocuSign, status is:" . $status . "\nerror text: "; print_r($json_response); echo "\n"; exit(-1); } $response = json_decode($json_response, true); $envelopeId = $response["envelopeId"]; error_log ("successfully created envelope: $envelopeId"); $url = getSignatureURL($envelopeId, $recipientName, $recipientEmail, $recipientID); return $url; }//c_requestSignature()... The function getSignatureURL() has code as follows: function getSignatureURL($envelopeId, $recipientName, $recipientEmail, $recipientID){ //function retrieves the signing ceremony UX URL from DocuSign $baseURL = c_docusignBaseURL(); $accountId = c_docusignAccountId(); $header = c_docusignHeader(); //set up the data we'll send to the Docusign server $data = array("returnUrl" => "http://_redacted_", "authenticationMethod" => "none", "email" => $recipientEmail, "name" => $recipientName, "recipientId" => $recipientID, //"recipientId" => "1", //"clientUserId" => $recipientID, "userName" => $recipientName ); $data_string = json_encode($data); //set up curl $curl = curl_init($baseURL . "/envelopes/$envelopeId/views/recipient" ); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Content-Length: ' . strlen($data_string), "X-DocuSign-Authentication: $header" ) ); //make the API call $json_response = curl_exec($curl); $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ( $status != 201 ) { echo "error calling webservice, status is:" . $status . "\nerror text is --> "; print_r($json_response); echo "\n"; exit(-1); } //retrieve and process the response $response = json_decode($json_response, true); return $response["url"]; } UPDATE 2 Here's the raw json as requested... { "emailSubject": "some subject", "status": "sent", "compositeTemplates": [ { "serverTemplates": [ { "sequence": "1", "templateId": "_redacted_" } ], "inlineTemplates": [ { "sequence": "2", "recipients": { "signers": [ { "name": "Andrew Tester1", "email": "my_email_address", "roleName": "NewHire", "recipientId": "1234", "clientUserId": "1234" } ] } } ], "document": { "documentId": "1", "name": "W4", "fileExtension": "pdf", "documentBase64": "_redacted_" } } ] } Update 3 I had a problem which was preventing me from seeing the proper output of the above json. With that fixed, now I'm getting the following error: Error calling DocuSign, status is:400 error text: { "errorCode": "TAB_REFERS_TO_MISSING_DOCUMENT", "message": "The DocumentId specified in the tab element does not refer to a document in this envelope. Tab refers to DocumentId 46677269 which is not present." } If I change the document stanza above as follows: "document": { "documentId": "46677269", "name": "W4", "fileExtension": "pdf", "documentBase64": "_redacted_" } The error goes away, but I still get a signing ceremony with no tabs.
The following request can be used to create an envelope from the Server Template. The server templates document will be replaced with the new document that is specified in the request. { "emailSubject": "Test Email Subject", "emailBlurb" : "Test Email Body", "status": "sent", "compositeTemplates": [ { "serverTemplates": [ { "sequence": "1", "templateId": "86841739-f12d-460e-9807-23a9b90cff6b" } ], "inlineTemplates": [ { "sequence": "1", "recipients": { "signers": [ { "name": "Jane Doe", "email": "janedoe#acme.com", "roleName": "New Employee" } ] } } ], "document": { "documentId": "1", "name": "Your Doc Name", "fileExtension": "pdf", "documentBase64": "" } } ] }
Well this was a thorny problem, but I found the solution (finally), with some help form the folk at Docusign. I thought I'd post it here for those who might run into this in the future. Solution The json structure passed to the DocuSign API is extremely important. If there are any errors in it at all, it won't work right, and the error message is not always helpful. Furthermore, in what I was doing, the specific parameters passed were also crucial. The envelope generation code above is correct, though with the caveat that you must specify the PDF document ID that is part of the template stored on DocuSign's servers. You can query this via their API given the envelope ID (which is what I'm doing). Apparently this didn't use to be required, but now it is and there's no documentation anywhere stating that. My fundamental problem with the signature tabs though, was the code requesting the signing ceremony URL. I had extra parameters which were being accepted without error, but were messing things up. Discovered this, by using DocuSign's REST API explorer to generate a working signing ceremony URL (complete with all the proper signature tabs), and comparing the output json whith what I was trying to pass in my code. Here's the working PHP code that generates the correct json: $data = array( "authenticationMethod" => "email", "clientUserId" => $recipientID, "email" => $recipientEmail, "returnUrl" => "_redacted_", "userName" => $recipientName ); $data_string = json_encode($data);
Can't put an anchor in the right place
I'm trying to add an anchor to a xml document (word document), but its not working for some reason. I'm following https://www.docusign.com/developer-center/explore/features/stick-etabs, section Tab Placement Method 2: Auto-Place (Anchor Tagging). That is the result I'm having: I tried to adjust anchorXOffset and anchorYOffset properties. I'm trying to put the sign after the "Yours sincerely" text: request_hash = { 'status' => 'sent', 'emailBlurb' => 'eblurb', 'emailSubject' => 'Hello, you have a contract file to be signed. Hurry up!', 'documents' => [ { 'name' => file_name, 'documentId' => '1', 'order' => '1' } ], 'recipients' => { 'signers' => [ { # Employee 'email' => user_email, 'name' => user_name, 'recipientId' => '2', "tabs" => { "signHereTabs" => [{ #"xPosition" => "120", #"yPosition" => "110", "anchorString": "SIGNED", "anchorXOffset": "1", "anchorYOffset": "0", "anchorIgnoreIfNotPresent": "true", "anchorUnits": "inches", "documentId" => "1", "pageNumber" => "11" }] } }, { # The owner 'email' => ENV['manager_email'], 'name' => ENV['manager_name'], 'recipientId' => '1', "tabs" => { "signHereTabs" => [{ #"xPosition" => "70", #"yPosition" => "500", "anchorString": "Yours sincerely", "anchorXOffset": "0", "anchorYOffset": "0", "anchorIgnoreIfNotPresent": "true", "anchorUnits": "inches", "documentId" => "1", "pageNumber" => "10" }] } } ] } }
I suggest starting with a single word anchor string, eg "sincerely". Also, remove "pageNumber" from the signHereTabs object. It shouldn't be used while you're using anchor text positioning. Lastly, check out the anchor text recipe for more information and a working example.
DocuSign REST API - can't control Document Visibility on Envelopes from Documents?
The Docusign REST API describes a way to control document visibility when creating envelopes from documents: https://docs.docusign.com/esign/restapi/Envelopes/Envelopes/create/ The option is enforceSignerVisibility. However when I attempt to use this option, the visibility is NOT limited. Am I doing something wrong? I am using a modified version of the PHP DocuSign helper library (some features/options added). Here is a test case I created. In this case, there are two signers and two documents. Signer 1 has a signature on Document 1 and Signer 2 has a signature on Document 2. The goal is that Signer 1 would only see Document 1 and Signer 2 would only see Document 2. However, the below example results in both signers seeing both documents: Code <?php $client = new DocuSign_Client; $service = new DocuSign_RequestSignatureService($client); $documents = array( new DocuSign_Document( "TestDoc1", 1, file_get_contents( $_SERVER['DOCUMENT_ROOT'].'/sandbox/ncg/test1.pdf' ) ), new DocuSign_Document( "TestDoc2", 2, file_get_contents( $_SERVER['DOCUMENT_ROOT'].'/sandbox/ncg/test2.pdf' ) ) ); $signer1 = new DocuSign_Recipient( 1, 1, "Signer 1", "test.tfcornerstone+t1#gmail.com", NULL ); $signer1->setTab("signHereTabs",array( "anchorYOffset" => "0", "anchorXOffset" => "0", "anchorString" => "[__[Signer1]__]", "anchorIgnoreIfNotPresent" => true, ) ); $signer2 = new DocuSign_Recipient( 1, 2, "Signer 2", "test.tfcornerstone+t2#gmail.com", NULL ); $signer2->setTab("signHereTabs",array( "anchorYOffset" => "0", "anchorXOffset" => "0", "anchorString" => "[__[Signer2]__]", "anchorIgnoreIfNotPresent" => true, ) ); $recipients = array( $signer1, $signer2 ); $emailSubject = "Test Doc"; $emailBlurb = "Testing Visibility"; $status = 'sent'; // can be "created" or "sent" $eventNotifications = new DocuSign_EventNotification( $url, //url false, //loggingEnabled false, //requireAcknowledgment, false, //useSoapInterface, NULL, //soapNameSpace, false, //includeCertificateWithSoap, false, //signMessageWithX509Cert, false, //includeDocuments, false, //includeTimeZone, false, //includeSenderAccountAsCustomField, NULL, //envelopeEvents, array( "Completed", "Sent" ) //recipientEvents ); $options = array( "enforceSignerVisibility" => true, ); $response = $service->signature->createEnvelopeFromDocument( $emailSubject, $emailBlurb, $status, $documents, $recipients, $eventNotifications, $options ); d($response); CURL request Url: https://www.docusign.net/restapi/v2/accounts/XXXXX/envelopes Method: POST Headers: --myboundary Content-Type: application/json Content-Disposition: form-data {"emailSubject":"Test Doc","emailBlurb":"Testing Visibility","documents":[{"name":"TestDoc1","documentId":1},{"name":"TestDoc2","documentId":2}],"status":"sent","enforceSignerVisibility":true,"recipients":{"signers":[{"routingOrder":1,"recipientId":1,"name":"Signer 1","email":"test.tfcornerstone+t1#gmail.com","clientUserId":null,"tabs":{"signHereTabs":[{"anchorYOffset":"0","anchorXOffset":"0","anchorString":"[__[Signer1]__]","anchorIgnoreIfNotPresent":true}]},"embeddedRecipientStartUrl":null,"excludedDocuments":null},{"routingOrder":1,"recipientId":2,"name":"Signer 2","email":"test.tfcornerstone+t2#gmail.com","clientUserId":null,"tabs":{"signHereTabs":[{"anchorYOffset":"0","anchorXOffset":"0","anchorString":"[__[Signer2]__]","anchorIgnoreIfNotPresent":true}]},"embeddedRecipientStartUrl":null,"excludedDocuments":null}]},"eventNotification":{"loggingEnabled":false,"requireAcknowledgment":false,"useSoapInterface":false,"includeCertificateWithSoap":false,"signMessageWithX509Cert":false,"includeDocuments":false,"includeTimeZone":false,"includeSenderAccountAsCustomField":false,"recipientEvents":[{"recipientEventStatusCode":"Completed"},{"recipientEventStatusCode":"Sent"}]}} <<PDF CONTENT>>--myboundary-- Formatted JSON data { "emailSubject": "Test Doc", "emailBlurb": "Testing Visibility", "documents": [ { "name": "TestDoc1", "documentId": 1 }, { "name": "TestDoc2", "documentId": 2 } ], "status": "sent", "enforceSignerVisibility": true, "recipients": { "signers": [ { "routingOrder": 1, "recipientId": 1, "name": "Signer 1", "email": "test.tfcornerstone+t1#gmail.com", "clientUserId": null, "tabs": { "signHereTabs": [ { "anchorYOffset": "0", "anchorXOffset": "0", "anchorString": "[__[Signer1]__]", "anchorIgnoreIfNotPresent": true } ] }, "embeddedRecipientStartUrl": null, "excludedDocuments": null }, { "routingOrder": 1, "recipientId": 2, "name": "Signer 2", "email": "test.tfcornerstone+t2#gmail.com", "clientUserId": null, "tabs": { "signHereTabs": [ { "anchorYOffset": "0", "anchorXOffset": "0", "anchorString": "[__[Signer2]__]", "anchorIgnoreIfNotPresent": true } ] }, "embeddedRecipientStartUrl": null, "excludedDocuments": null } ] }, "eventNotification": { "loggingEnabled": false, "requireAcknowledgment": false, "useSoapInterface": false, "includeCertificateWithSoap": false, "signMessageWithX509Cert": false, "includeDocuments": false, "includeTimeZone": false, "includeSenderAccountAsCustomField": false, "recipientEvents": [ { "recipientEventStatusCode": "Completed" }, { "recipientEventStatusCode": "Sent" } ] } }
I don't believe DocVis can be set to "Off" in order to enforce it in the API. In Preferences -> Features change the DocVis dropdown to "Sender Can Set Must Sign To View Unless Sender Account" and give the same request another shot.